rack-oauth2-1.4.0/0000755000004100000410000000000012750322535013670 5ustar www-datawww-datarack-oauth2-1.4.0/Rakefile0000644000004100000410000000062012750322535015333 0ustar www-datawww-datarequire 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) namespace :coverage do desc "Open coverage report" task :report do require 'simplecov' `open "#{File.join SimpleCov.coverage_path, 'index.html'}"` end end task :spec do Rake::Task[:'coverage:report'].invoke unless ENV['TRAVIS_RUBY_VERSION'] end task default: :spec rack-oauth2-1.4.0/Gemfile0000644000004100000410000000013612750322535015163 0ustar www-datawww-datasource 'http://rubygems.org' platforms :jruby do gem 'jruby-openssl', '>= 0.7' end gemspecrack-oauth2-1.4.0/.rspec0000644000004100000410000000003712750322535015005 0ustar www-datawww-data--color --format=documentation rack-oauth2-1.4.0/spec/0000755000004100000410000000000012750322535014622 5ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/0000755000004100000410000000000012750322535017471 5ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/resources/0000755000004100000410000000000012750322535021503 5ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/resources/fake.txt0000644000004100000410000000000412750322535023144 0ustar www-datawww-datafakerack-oauth2-1.4.0/spec/mock_response/errors/0000755000004100000410000000000012750322535021005 5ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/errors/invalid_request.json0000644000004100000410000000011212750322535025070 0ustar www-datawww-data{ "error":"invalid_request", "error_description":"error description" }rack-oauth2-1.4.0/spec/mock_response/blank0000644000004100000410000000000012750322535020471 0ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/tokens/0000755000004100000410000000000012750322535020774 5ustar www-datawww-datarack-oauth2-1.4.0/spec/mock_response/tokens/legacy_without_expires_in.txt0000644000004100000410000000003112750322535027003 0ustar www-datawww-dataaccess_token=access_tokenrack-oauth2-1.4.0/spec/mock_response/tokens/unknown.json0000644000004100000410000000016512750322535023370 0ustar www-datawww-data{ "access_token":"access_token", "refresh_token":"refresh_token", "token_type":"unknown", "expires_in":3600 }rack-oauth2-1.4.0/spec/mock_response/tokens/bearer.json0000644000004100000410000000016412750322535023130 0ustar www-datawww-data{ "access_token":"access_token", "refresh_token":"refresh_token", "token_type":"bearer", "expires_in":3600 }rack-oauth2-1.4.0/spec/mock_response/tokens/legacy.json0000644000004100000410000000013312750322535023130 0ustar www-datawww-data{ "access_token":"access_token", "refresh_token":"refresh_token", "expires_in":3600 }rack-oauth2-1.4.0/spec/mock_response/tokens/mac.json0000644000004100000410000000025212750322535022426 0ustar www-datawww-data{ "token_type":"mac", "mac_algorithm":"hmac-sha-256", "expires_in":3600, "mac_key":"secret", "refresh_token":"refresh_token", "access_token":"access_token" } rack-oauth2-1.4.0/spec/mock_response/tokens/_Bearer.json0000644000004100000410000000016412750322535023227 0ustar www-datawww-data{ "access_token":"access_token", "refresh_token":"refresh_token", "token_type":"Bearer", "expires_in":3600 }rack-oauth2-1.4.0/spec/mock_response/tokens/legacy.txt0000644000004100000410000000004612750322535023001 0ustar www-datawww-dataaccess_token=access_token&expires=3600rack-oauth2-1.4.0/spec/spec_helper.rb0000644000004100000410000000060512750322535017441 0ustar www-datawww-datarequire 'simplecov' SimpleCov.start do add_filter 'spec' end require 'rspec' require 'rspec/its' require 'rack/oauth2' RSpec.configure do |config| config.expect_with :rspec do |c| c.syntax = [:should, :expect] end end require 'helpers/time' require 'helpers/webmock_helper' def simple_app lambda do |env| [ 200, {'Content-Type' => 'text/plain'}, ["HELLO"] ] end end rack-oauth2-1.4.0/spec/helpers/0000755000004100000410000000000012750322535016264 5ustar www-datawww-datarack-oauth2-1.4.0/spec/helpers/time.rb0000644000004100000410000000050612750322535017550 0ustar www-datawww-dataclass Time class << self module NowWithFixedTime def now if @fixed_time @fixed_time.dup else super end end end prepend NowWithFixedTime def fix(time = Time.now) @fixed_time = time yield ensure @fixed_time = nil end end end rack-oauth2-1.4.0/spec/helpers/webmock_helper.rb0000644000004100000410000000163512750322535021604 0ustar www-datawww-datarequire 'webmock/rspec' module WebMockHelper def mock_response(method, endpoint, response_file, options = {}) stub_request(method, endpoint).with( request_for(method, options) ).to_return( response_for(response_file, options) ) end private def request_for(method, options = {}) request = {} params = options.try(:[], :params) || {} case method when :post, :put, :delete request[:body] = params else request[:query] = params end if options[:request_header] request[:headers] = options[:request_header] end request end def response_for(response_file, options = {}) response = {} response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', response_file)) if options[:status] response[:status] = options[:status] end response end end include WebMockHelper WebMock.disable_net_connect!rack-oauth2-1.4.0/spec/rack/0000755000004100000410000000000012750322535015542 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/0000755000004100000410000000000012750322535016744 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/0000755000004100000410000000000012750322535020252 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/authorize_spec.rb0000644000004100000410000001517712750322535023636 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Authorize do let(:app) { Rack::OAuth2::Server::Authorize.new } let(:request) { Rack::MockRequest.new app } let(:redirect_uri) { 'http://client.example.com/callback' } let(:bad_request) { Rack::OAuth2::Server::Authorize::BadRequest } context 'when response_type is missing' do it do expect { request.get "/?client_id=client&redirect_uri=#{redirect_uri}" }.to raise_error bad_request end end context 'when redirect_uri is missing' do it do expect { request.get "/?response_type=code&client_id=client" }.not_to raise_error end end context 'when client_id is missing' do it do expect { request.get "/?response_type=code&redirect_uri=#{redirect_uri}" }.to raise_error bad_request end end context 'when unknown response_type is given' do it do expect { request.get "/?response_type=unknown&client_id=client&redirect_uri=#{redirect_uri}" }.to raise_error bad_request end end context 'when all required parameters are valid' do [:code, :token].each do |request_type| context "when response_type = :#{request_type}" do subject { request.get "/?response_type=#{request_type}&client_id=client&redirect_uri=#{redirect_uri}" } its(:status) { should == 200 } end end end describe Rack::OAuth2::Server::Authorize::Request do let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client&redirect_uri=#{redirect_uri}") } let(:request) { Rack::OAuth2::Server::Authorize::Request.new env } describe '#varified_redirect_uri' do context 'when an Array of pre-registered URIs are given' do context 'when given redirect_uri is valid against one of them' do let :pre_registered do [ redirect_uri, 'http://ja.client.example.com/callback', 'http://en.client.example.com/callback' ] end it 'should be valid' do request.verify_redirect_uri!(pre_registered).should == redirect_uri end end context 'otherwise' do let :pre_registered do [ 'http://ja.client.example.com/callback', 'http://en.client.example.com/callback' ] end it do expect do request.verify_redirect_uri!(pre_registered) end.to raise_error bad_request end end end context 'when exact mathed redirect_uri is given' do let(:pre_registered) { redirect_uri } it 'should be valid' do request.verify_redirect_uri!(pre_registered).should == redirect_uri end end context 'when partially mathed redirect_uri is given' do let(:pre_registered) { 'http://client.example.com' } context 'when partial matching allowed' do it 'should be valid' do request.verify_redirect_uri!(pre_registered, :allow_partial_match).should == redirect_uri end end context 'otherwise' do it do expect do request.verify_redirect_uri!(pre_registered) end.to raise_error bad_request end end end context 'when invalid redirect_uri is given' do let(:pre_registered) { 'http://client2.example.com' } it do expect do request.verify_redirect_uri!(pre_registered) end.to raise_error bad_request end end context 'when redirect_uri is missing' do let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client") } context 'when pre-registered redirect_uri is a String' do let(:pre_registered) { redirect_uri } it 'should use pre-registered redirect_uri' do request.verify_redirect_uri!(pre_registered).should == pre_registered end end context 'when pre-registered redirect_uri is an Array' do context 'when only 1' do let(:pre_registered) { [redirect_uri] } context 'when partial match allowed' do it do expect do request.verify_redirect_uri!(pre_registered, :allow_partial_match) end.to raise_error bad_request end end context 'otherwise' do it 'should use pre-registered redirect_uri' do request.verify_redirect_uri!(pre_registered).should == pre_registered.first end end end context 'when more than 2' do let(:pre_registered) { [redirect_uri, 'http://client.example.com/callback2'] } it do expect do request.verify_redirect_uri!(pre_registered) end.to raise_error bad_request end end end end end end describe 'extensibility' do before do require 'rack/oauth2/server/authorize/extension/code_and_token' end let(:env) do Rack::MockRequest.env_for("/authorize?response_type=#{response_type}&client_id=client") end let(:request) { Rack::OAuth2::Server::Authorize::Request.new env } its(:extensions) { should == [Rack::OAuth2::Server::Authorize::Extension::CodeAndToken] } describe 'code token' do let(:response_type) { 'code%20token' } it do app.send( :response_type_for, request ).should == Rack::OAuth2::Server::Authorize::Extension::CodeAndToken end end describe 'token code' do let(:response_type) { 'token%20code' } it do app.send( :response_type_for, request ).should == Rack::OAuth2::Server::Authorize::Extension::CodeAndToken end end describe 'token code id_token' do let(:response_type) { 'token%20code%20id_token' } it do expect do app.send(:response_type_for, request) end.to raise_error bad_request end end describe 'id_token' do before do class Rack::OAuth2::Server::Authorize::Extension::IdToken < Rack::OAuth2::Server::Abstract::Handler def self.response_type_for?(response_type) response_type == 'id_token' end end end its(:extensions) do should == [ Rack::OAuth2::Server::Authorize::Extension::CodeAndToken, Rack::OAuth2::Server::Authorize::Extension::IdToken ] end let(:response_type) { 'id_token' } it do app.send( :response_type_for, request ).should == Rack::OAuth2::Server::Authorize::Extension::IdToken end end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/resource_spec.rb0000644000004100000410000000115312750322535023440 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource do subject { Rack::OAuth2::Server::Resource.new(simple_app, 'realm') } its(:realm) { should == 'realm' } end describe Rack::OAuth2::Server::Resource::Request do let(:env) { Rack::MockRequest.env_for('/protected_resource') } let(:request) { Rack::OAuth2::Server::Resource::Request.new(env) } describe '#setup!' do it do expect { request.setup! }.to raise_error(RuntimeError, 'Define me!') end end describe '#oauth2?' do it do expect { request.oauth2? }.to raise_error(RuntimeError, 'Define me!') end end endrack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/0000755000004100000410000000000012750322535022264 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/error_spec.rb0000644000004100000410000000743712750322535024767 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Authorize::BadRequest do let(:klass) { Rack::OAuth2::Server::Authorize::BadRequest } let(:error) { klass.new(:invalid_request) } let(:redirect_uri) { 'http://client.example.com/callback' } subject { error } it { should be_a Rack::OAuth2::Server::Abstract::BadRequest } its(:protocol_params) do should == { error: :invalid_request, error_description: nil, error_uri: nil, state: nil } end describe '#finish' do context 'when redirect_uri is given' do before { error.redirect_uri = redirect_uri } context 'when protocol_params_location = :query' do before { error.protocol_params_location = :query } it 'should redirect with error in query' do state, header, response = error.finish state.should == 302 header["Location"].should == "#{redirect_uri}?error=invalid_request" end end context 'when protocol_params_location = :fragment' do before { error.protocol_params_location = :fragment } it 'should redirect with error in fragment' do state, header, response = error.finish state.should == 302 header["Location"].should == "#{redirect_uri}#error=invalid_request" end end context 'otherwise' do before { error.protocol_params_location = :other } it 'should redirect without error' do state, header, response = error.finish state.should == 302 header["Location"].should == redirect_uri end end end context 'otherwise' do it 'should raise itself' do expect { error.finish }.to raise_error(klass) { |e| e.should == error } end end end end describe Rack::OAuth2::Server::Authorize::ErrorMethods do let(:klass) { Rack::OAuth2::Server::Authorize::BadRequest } let(:redirect_uri) { 'http://client.example.com/callback' } let(:default_description) { Rack::OAuth2::Server::Authorize::ErrorMethods::DEFAULT_DESCRIPTION } let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") } let(:request) { Rack::OAuth2::Server::Authorize::Request.new env } let(:request_for_code) { Rack::OAuth2::Server::Authorize::Code::Request.new env } let(:request_for_token) { Rack::OAuth2::Server::Authorize::Token::Request.new env } describe 'bad_request!' do it do expect { request.bad_request! }.to raise_error klass end context 'when response_type = :code' do it 'should set protocol_params_location = :query' do expect { request_for_code.bad_request! }.to raise_error(klass) { |e| e.protocol_params_location.should == :query } end end context 'when response_type = :token' do it 'should set protocol_params_location = :fragment' do expect { request_for_token.bad_request! }.to raise_error(klass) { |e| e.protocol_params_location.should == :fragment } end end end Rack::OAuth2::Server::Authorize::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code| method = "#{error_code}!" klass = case error_code when :server_error Rack::OAuth2::Server::Authorize::ServerError when :temporarily_unavailable Rack::OAuth2::Server::Authorize::TemporarilyUnavailable else Rack::OAuth2::Server::Authorize::BadRequest end describe method do it "should raise #{klass} with error = :#{error_code}" do klass = expect { request.send method }.to raise_error(klass) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/extensions/0000755000004100000410000000000012750322535024463 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb0000644000004100000410000000431212750322535030756 0ustar www-datawww-datarequire 'spec_helper.rb' require 'rack/oauth2/server/authorize/extension/code_and_token' describe Rack::OAuth2::Server::Authorize::Extension::CodeAndToken do let(:request) { Rack::MockRequest.new app } let(:redirect_uri) { 'http://client.example.com/callback' } let(:access_token) { 'access_token' } let(:authorization_code) { 'authorization_code' } let(:response) do request.get("/?response_type=code%20token&client_id=client&redirect_uri=#{redirect_uri}") end context "when approved" do subject { response } let(:bearer_token) { Rack::OAuth2::AccessToken::Bearer.new(access_token: access_token) } let :app do Rack::OAuth2::Server::Authorize.new do |request, response| response.redirect_uri = redirect_uri response.access_token = bearer_token response.code = authorization_code response.approve! end end its(:status) { should == 302 } its(:location) { should include "#{redirect_uri}#" } its(:location) { should include "code=#{authorization_code}"} its(:location) { should include "access_token=#{access_token}"} its(:location) { should include 'token_type=bearer' } context 'when refresh_token is given' do let :bearer_token do Rack::OAuth2::AccessToken::Bearer.new( access_token: access_token, refresh_token: 'refresh' ) end its(:location) { should include "#{redirect_uri}#" } its(:location) { should include "code=#{authorization_code}"} its(:location) { should include "access_token=#{access_token}"} its(:location) { should include 'token_type=bearer' } end end context 'when denied' do let :app do Rack::OAuth2::Server::Authorize.new do |request, response| request.verify_redirect_uri! redirect_uri request.access_denied! end end it 'should redirect with error in fragment' do response.status.should == 302 error_message = { error: :access_denied, error_description: Rack::OAuth2::Server::Authorize::ErrorMethods::DEFAULT_DESCRIPTION[:access_denied] } response.location.should == "#{redirect_uri}##{error_message.to_query}" end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/token_spec.rb0000644000004100000410000000457712750322535024760 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Authorize::Token do let(:request) { Rack::MockRequest.new app } let(:redirect_uri) { 'http://client.example.com/callback' } let(:access_token) { 'access_token' } let(:response) { request.get("/?response_type=token&client_id=client&redirect_uri=#{redirect_uri}&state=state") } context "when approved" do subject { response } let(:bearer_token) { Rack::OAuth2::AccessToken::Bearer.new(access_token: access_token) } let :app do Rack::OAuth2::Server::Authorize.new do |request, response| response.redirect_uri = redirect_uri response.access_token = bearer_token response.approve! end end its(:status) { should == 302 } its(:location) { should == "#{redirect_uri}#access_token=#{access_token}&state=state&token_type=bearer" } context 'when refresh_token is given' do let :bearer_token do Rack::OAuth2::AccessToken::Bearer.new( access_token: access_token, refresh_token: 'refresh' ) end its(:location) { should == "#{redirect_uri}#access_token=#{access_token}&state=state&token_type=bearer" } end context 'when redirect_uri is missing' do let :app do Rack::OAuth2::Server::Authorize.new do |request, response| response.access_token = bearer_token response.approve! end end it do expect { response }.to raise_error AttrRequired::AttrMissing end end context 'when access_token is missing' do let :app do Rack::OAuth2::Server::Authorize.new do |request, response| response.redirect_uri = redirect_uri response.approve! end end it do expect { response }.to raise_error AttrRequired::AttrMissing end end end context 'when denied' do let :app do Rack::OAuth2::Server::Authorize.new do |request, response| request.verify_redirect_uri! redirect_uri request.access_denied! end end it 'should redirect with error in fragment' do response.status.should == 302 error_message = { error: :access_denied, error_description: Rack::OAuth2::Server::Authorize::ErrorMethods::DEFAULT_DESCRIPTION[:access_denied] } response.location.should == "#{redirect_uri}##{error_message.to_query}&state=state" end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/authorize/code_spec.rb0000644000004100000410000000362412750322535024542 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Authorize::Code do let(:request) { Rack::MockRequest.new app } let(:redirect_uri) { 'http://client.example.com/callback' } let(:authorization_code) { 'authorization_code' } let(:response) { request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state" } context 'when approved' do subject { response } let :app do Rack::OAuth2::Server::Authorize.new do |request, response| response.redirect_uri = redirect_uri response.code = authorization_code response.approve! end end its(:status) { should == 302 } its(:location) { should == "#{redirect_uri}?code=#{authorization_code}&state=state" } context 'when redirect_uri already includes query' do let(:redirect_uri) { 'http://client.example.com/callback?k=v' } its(:location) { should == "#{redirect_uri}&code=#{authorization_code}&state=state" } end context 'when redirect_uri is missing' do let(:redirect_uri) { nil } it do expect { response }.to raise_error AttrRequired::AttrMissing end end context 'when code is missing' do let(:authorization_code) { nil } it do expect { response }.to raise_error AttrRequired::AttrMissing end end end context 'when denied' do let :app do Rack::OAuth2::Server::Authorize.new do |request, response| request.verify_redirect_uri! redirect_uri request.access_denied! end end it 'should redirect with error in query' do response.status.should == 302 error_message = { error: :access_denied, error_description: Rack::OAuth2::Server::Authorize::ErrorMethods::DEFAULT_DESCRIPTION[:access_denied] } response.location.should == "#{redirect_uri}?#{error_message.to_query}&state=state" end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/resource/0000755000004100000410000000000012750322535022101 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/resource/mac/0000755000004100000410000000000012750322535022641 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/resource/mac/error_spec.rb0000644000004100000410000000335112750322535025333 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource::MAC::Unauthorized do let(:error) { Rack::OAuth2::Server::Resource::MAC::Unauthorized.new(:invalid_token) } it { should be_a Rack::OAuth2::Server::Resource::Unauthorized } describe '#scheme' do subject { error } its(:scheme) { should == :MAC } end describe '#finish' do it 'should use MAC scheme' do status, header, response = error.finish header['WWW-Authenticate'].should =~ /^MAC / end end end describe Rack::OAuth2::Server::Resource::MAC::ErrorMethods do let(:unauthorized) { Rack::OAuth2::Server::Resource::MAC::Unauthorized } let(:redirect_uri) { 'http://client.example.com/callback' } let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION } let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") } let(:request) { Rack::OAuth2::Server::Resource::MAC::Request.new env } describe 'unauthorized!' do it do expect { request.unauthorized! :invalid_client }.to raise_error unauthorized end end Rack::OAuth2::Server::Resource::Bearer::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code| method = "#{error_code}!" case error_code when :invalid_request # ignore when :insufficient_scope # ignore else describe method do it "should raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized with error = :#{error_code}" do expect { request.send method }.to raise_error(unauthorized) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end end end endrack-oauth2-1.4.0/spec/rack/oauth2/server/resource/bearer/0000755000004100000410000000000012750322535023341 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/resource/bearer/error_spec.rb0000644000004100000410000000340412750322535026032 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource::Bearer::Unauthorized do let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:invalid_token) } it { should be_a Rack::OAuth2::Server::Resource::Unauthorized } describe '#scheme' do subject { error } its(:scheme) { should == :Bearer } end describe '#finish' do it 'should use Bearer scheme' do status, header, response = error.finish header['WWW-Authenticate'].should include 'Bearer' end end end describe Rack::OAuth2::Server::Resource::Bearer::ErrorMethods do let(:unauthorized) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized } let(:redirect_uri) { 'http://client.example.com/callback' } let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION } let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") } let(:request) { Rack::OAuth2::Server::Resource::Bearer::Request.new env } describe 'unauthorized!' do it do expect { request.unauthorized! :invalid_client }.to raise_error unauthorized end end Rack::OAuth2::Server::Resource::Bearer::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code| method = "#{error_code}!" case error_code when :invalid_request # ignore when :insufficient_scope # ignore else describe method do it "should raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized with error = :#{error_code}" do expect { request.send method }.to raise_error(unauthorized) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end end end endrack-oauth2-1.4.0/spec/rack/oauth2/server/resource/error_spec.rb0000644000004100000410000001205512750322535024574 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource::BadRequest do let(:error) { Rack::OAuth2::Server::Resource::BadRequest.new(:invalid_request) } it { should be_a Rack::OAuth2::Server::Abstract::BadRequest } describe '#finish' do it 'should respond in JSON' do status, header, response = error.finish status.should == 400 header['Content-Type'].should == 'application/json' response.body.should == ['{"error":"invalid_request"}'] end end end describe Rack::OAuth2::Server::Resource::Unauthorized do let(:error) { Rack::OAuth2::Server::Resource::Unauthorized.new(:invalid_token) } let(:realm) { Rack::OAuth2::Server::Resource::DEFAULT_REALM } it { should be_a Rack::OAuth2::Server::Abstract::Unauthorized } describe '#scheme' do it do expect { error.scheme }.to raise_error(RuntimeError, 'Define me!') end end context 'when scheme is defined' do let :error_with_scheme do e = error e.instance_eval do def scheme :Scheme end end e end describe '#finish' do it 'should respond in JSON' do status, header, response = error_with_scheme.finish status.should == 401 header['Content-Type'].should == 'application/json' header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\", error=\"invalid_token\"" response.body.should == ['{"error":"invalid_token"}'] end context 'when error_code is not invalid_token' do let(:error) { Rack::OAuth2::Server::Resource::Unauthorized.new(:something) } it 'should have error_code in body but not in WWW-Authenticate header' do status, header, response = error_with_scheme.finish header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\"" response.body.first.should include '"error":"something"' end end context 'when realm is specified' do let(:realm) { 'server.example.com' } let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:something, nil, realm: realm) } it 'should use given realm' do status, header, response = error_with_scheme.finish header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\"" response.body.first.should include '"error":"something"' end end end end end describe Rack::OAuth2::Server::Resource::Forbidden do let(:error) { Rack::OAuth2::Server::Resource::Forbidden.new(:insufficient_scope) } it { should be_a Rack::OAuth2::Server::Abstract::Forbidden } describe '#finish' do it 'should respond in JSON' do status, header, response = error.finish status.should == 403 header['Content-Type'].should == 'application/json' response.body.should == ['{"error":"insufficient_scope"}'] end end context 'when scope option is given' do let(:error) { Rack::OAuth2::Server::Resource::Bearer::Forbidden.new(:insufficient_scope, 'Desc', scope: [:scope1, :scope2]) } it 'should have blank WWW-Authenticate header' do status, header, response = error.finish response.body.first.should include '"scope":"scope1 scope2"' end end end describe Rack::OAuth2::Server::Resource::Bearer::ErrorMethods do let(:bad_request) { Rack::OAuth2::Server::Resource::BadRequest } let(:forbidden) { Rack::OAuth2::Server::Resource::Forbidden } let(:redirect_uri) { 'http://client.example.com/callback' } let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION } let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") } let(:request) { Rack::OAuth2::Server::Resource::Request.new env } describe 'bad_request!' do it do expect { request.bad_request! :invalid_request }.to raise_error bad_request end end describe 'unauthorized!' do it do expect { request.unauthorized! :invalid_client }.to raise_error(RuntimeError, 'Define me!') end end Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code| method = "#{error_code}!" case error_code when :invalid_request describe method do it "should raise Rack::OAuth2::Server::Resource::BadRequest with error = :#{error_code}" do expect { request.send method }.to raise_error(bad_request) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end when :insufficient_scope describe method do it "should raise Rack::OAuth2::Server::Resource::Forbidden with error = :#{error_code}" do expect { request.send method }.to raise_error(forbidden) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end else describe method do it do expect { request.send method }.to raise_error(RuntimeError, 'Define me!') end end end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/resource/bearer_spec.rb0000644000004100000410000000763612750322535024714 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource::Bearer do let(:app) do Rack::OAuth2::Server::Resource::Bearer.new(simple_app) do |request| case request.access_token when 'valid_token' bearer_token when 'insufficient_scope_token' request.insufficient_scope! else request.invalid_token! end end end let(:bearer_token) do Rack::OAuth2::AccessToken::Bearer.new(access_token: 'valid_token') end let(:access_token) { env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN] } let(:request) { app.call(env) } subject { app.call(env) } shared_examples_for :authenticated_bearer_request do it 'should be authenticated' do status, header, response = request status.should == 200 access_token.should == bearer_token end end shared_examples_for :unauthorized_bearer_request do it 'should be unauthorized' do status, header, response = request status.should == 401 header['WWW-Authenticate'].should include 'Bearer' access_token.should be_nil end end shared_examples_for :bad_bearer_request do it 'should be bad_request' do status, header, response = request status.should == 400 access_token.should be_nil end end shared_examples_for :skipped_authentication_request do it 'should skip OAuth 2.0 authentication' do status, header, response = request status.should == 200 access_token.should be_nil end end context 'when no access token is given' do let(:env) { Rack::MockRequest.env_for('/protected_resource') } it_behaves_like :skipped_authentication_request end context 'when valid_token is given' do context 'when token is in Authorization header' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer valid_token') } it_behaves_like :authenticated_bearer_request end context 'when token is in params' do let(:env) { Rack::MockRequest.env_for('/protected_resource', params: {access_token: 'valid_token'}) } it_behaves_like :authenticated_bearer_request end end context 'when invalid authorization header is given' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => '') } it_behaves_like :skipped_authentication_request end context 'when invalid_token is given' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer invalid_token') } context 'when token is in Authorization header' do it_behaves_like :unauthorized_bearer_request end context 'when token is in params' do let(:env) { Rack::MockRequest.env_for('/protected_resource', params: {access_token: 'invalid_token'}) } it_behaves_like :unauthorized_bearer_request end describe 'realm' do context 'when specified' do let(:realm) { 'server.example.com' } let(:app) do Rack::OAuth2::Server::Resource::Bearer.new(simple_app, realm) do |request| request.unauthorized! end end it 'should use specified realm' do status, header, response = request header['WWW-Authenticate'].should include "Bearer realm=\"#{realm}\"" end end context 'otherwize' do it 'should use default realm' do status, header, response = request header['WWW-Authenticate'].should include "Bearer realm=\"#{Rack::OAuth2::Server::Resource::Bearer::DEFAULT_REALM}\"" end end end end context 'when multiple access_token is given' do context 'when token is in Authorization header and params' do let(:env) do Rack::MockRequest.env_for( '/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer valid_token', params: {access_token: 'valid_token'} ) end it_behaves_like :bad_bearer_request end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/resource/mac_spec.rb0000644000004100000410000001022712750322535024202 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Resource::MAC do let(:app) do Rack::OAuth2::Server::Resource::MAC.new(simple_app) do |request| case request.access_token when 'valid_token' token = mac_token token.verify!(request) token when 'insufficient_scope_token' request.insufficient_scope! else request.invalid_token! end end end let(:mac_token) do Rack::OAuth2::AccessToken::MAC.new( access_token: 'valid_token', mac_key: 'secret', mac_algorithm: 'hmac-sha-256', ts: 1305820230 # fix verification time ) end let(:access_token) { env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN] } let(:request) { app.call(env) } subject { app.call(env) } shared_examples_for :non_mac_request do it 'should skip OAuth 2.0 authentication' do status, header, response = request status.should == 200 access_token.should be_nil end end shared_examples_for :authenticated_mac_request do it 'should be authenticated' do status, header, response = request status.should == 200 access_token.should == mac_token end end shared_examples_for :unauthorized_mac_request do it 'should be unauthorized' do status, header, response = request status.should == 401 header['WWW-Authenticate'].should include 'MAC' access_token.should be_nil end end shared_examples_for :bad_mac_request do it 'should be unauthorized' do status, header, response = request status.should == 400 access_token.should be_nil end end context 'when no access token is given' do let(:env) { Rack::MockRequest.env_for('/protected_resource') } it 'should skip OAuth 2.0 authentication' do status, header, response = request status.should == 200 access_token.should be_nil end end context 'when valid_token is given' do context 'when other required params are missing' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token"') } it_behaves_like :unauthorized_mac_request end context 'when other required params are invalid' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305820234", mac="invalid""') } it_behaves_like :unauthorized_mac_request end context 'when all required params are valid' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305820234", mac="26JP6MMZyAHLHeMU8+m+NbVJgZbikp5SlT86/a62pwg="') } it_behaves_like :authenticated_mac_request end context 'when all required params are valid and ts is expired' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="valid_token", nonce="51e74de734c05613f37520872e68db5f", ts="1305819234", mac="nuo4765MZrVL/qMsAtuTczhqZAE5y02ChaLCyOiVU68="') } it_behaves_like :unauthorized_mac_request end end context 'when invalid_token is given' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="invalid_token"') } it_behaves_like :unauthorized_mac_request describe 'realm' do let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'MAC id="invalid_token"') } context 'when specified' do let(:realm) { 'server.example.com' } let(:app) do Rack::OAuth2::Server::Resource::MAC.new(simple_app, realm) do |request| request.unauthorized! end end it 'should use specified realm' do status, header, response = request header['WWW-Authenticate'].should include "MAC realm=\"#{realm}\"" end end context 'otherwize' do it 'should use default realm' do status, header, response = request header['WWW-Authenticate'].should include "MAC realm=\"#{Rack::OAuth2::Server::Resource::DEFAULT_REALM}\"" end end end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/abstract/0000755000004100000410000000000012750322535022055 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/abstract/error_spec.rb0000644000004100000410000000330612750322535024547 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Abstract::Error do context 'when full attributes are given' do subject do Rack::OAuth2::Server::Abstract::Error.new 400, :invalid_request, 'Missing some required params', uri: 'http://server.example.com/error' end its(:status) { should == 400 } its(:error) { should == :invalid_request } its(:description) { should == 'Missing some required params' } its(:uri) { should == 'http://server.example.com/error' } its(:protocol_params) do should == { error: :invalid_request, error_description: 'Missing some required params', error_uri: 'http://server.example.com/error' } end end context 'when optional attributes are not given' do subject do Rack::OAuth2::Server::Abstract::Error.new 400, :invalid_request end its(:status) { should == 400 } its(:error) { should == :invalid_request } its(:description) { should be_nil } its(:uri) { should be_nil } its(:protocol_params) do should == { error: :invalid_request, error_description: nil, error_uri: nil } end end end describe Rack::OAuth2::Server::Abstract::BadRequest do its(:status) { should == 400 } end describe Rack::OAuth2::Server::Abstract::Unauthorized do its(:status) { should == 401 } end describe Rack::OAuth2::Server::Abstract::Forbidden do its(:status) { should == 403 } end describe Rack::OAuth2::Server::Abstract::ServerError do its(:status) { should == 500 } end describe Rack::OAuth2::Server::Abstract::TemporarilyUnavailable do its(:status) { should == 503 } end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/0000755000004100000410000000000012750322535021372 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/server/token/client_credentials_spec.rb0000644000004100000410000000134612750322535026570 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::ClientCredentials do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'client_credentials', client_id: 'client_id', client_secret: 'client_secret' } end subject { request.post('/', params: params) } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/authorization_code_spec.rb0000644000004100000410000000250312750322535026623 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::AuthorizationCode do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'authorization_code', client_id: 'client_id', code: 'authorization_code', redirect_uri: 'http://client.example.com/callback' } end let(:response) { request.post('/', params: params) } subject { response } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } it 'should prevent to be cached' do response.header['Cache-Control'].should == 'no-store' response.header['Pragma'].should == 'no-cache' end [:code].each do |required| context "when #{required} is missing" do before do params.delete_if do |key, value| key == required end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/refresh_token_spec.rb0000644000004100000410000000203412750322535025566 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::RefreshToken do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: "refresh_token", client_id: "client_id", refresh_token: "refresh_token" } end subject { request.post('/', params: params) } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } context 'when refresh_token is missing' do before do params.delete_if do |key, value| key == :refresh_token end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/error_spec.rb0000644000004100000410000000532212750322535024064 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::BadRequest do let(:error) { Rack::OAuth2::Server::Token::BadRequest.new(:invalid_request) } it { should be_a Rack::OAuth2::Server::Abstract::BadRequest } describe '#finish' do it 'should respond in JSON' do status, header, response = error.finish status.should == 400 header['Content-Type'].should == 'application/json' response.body.should == ['{"error":"invalid_request"}'] end end end describe Rack::OAuth2::Server::Token::Unauthorized do let(:error) { Rack::OAuth2::Server::Token::Unauthorized.new(:invalid_request) } it { should be_a Rack::OAuth2::Server::Abstract::Unauthorized } describe '#finish' do it 'should respond in JSON' do status, header, response = error.finish status.should == 401 header['Content-Type'].should == 'application/json' header['WWW-Authenticate'].should == 'Basic realm="OAuth2 Token Endpoint"' response.body.should == ['{"error":"invalid_request"}'] end end end describe Rack::OAuth2::Server::Token::ErrorMethods do let(:bad_request) { Rack::OAuth2::Server::Token::BadRequest } let(:unauthorized) { Rack::OAuth2::Server::Token::Unauthorized } let(:redirect_uri) { 'http://client.example.com/callback' } let(:default_description) { Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION } let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") } let(:request) { Rack::OAuth2::Server::Token::Request.new env } describe 'bad_request!' do it do expect { request.bad_request! :invalid_request }.to raise_error bad_request end end describe 'unauthorized!' do it do expect { request.unauthorized! :invalid_client }.to raise_error unauthorized end end Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code| method = "#{error_code}!" case error_code when :invalid_client describe method do it "should raise Rack::OAuth2::Server::Token::Unauthorized with error = :#{error_code}" do expect { request.send method }.to raise_error(unauthorized) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end else describe method do it "should raise Rack::OAuth2::Server::Token::BadRequest with error = :#{error_code}" do expect { request.send method }.to raise_error(bad_request) { |error| error.error.should == error_code error.description.should == default_description[error_code] } end end end end endrack-oauth2-1.4.0/spec/rack/oauth2/server/token/saml2_bearer_spec.rb0000644000004100000410000000206012750322535025265 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::SAML2Bearer do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', client_id: 'client_id', assertion: '...' } end subject { request.post('/', params: params) } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } context 'when assertion is missing' do before do params.delete_if do |key, value| key == :assertion end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/jwt_bearer_spec.rb0000644000004100000410000000206612750322535025061 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::JWTBearer do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', client_id: 'client_id', assertion: 'header.payload.signature' } end subject { request.post('/', params: params) } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } context 'when assertion is missing' do before do params.delete_if do |key, value| key == :assertion end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end rack-oauth2-1.4.0/spec/rack/oauth2/server/token/password_spec.rb0000644000004100000410000000213412750322535024573 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Server::Token::Password do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'password', client_id: 'client_id', username: 'nov', password: 'secret' } end subject { request.post('/', params: params) } its(:status) { should == 200 } its(:content_type) { should == 'application/json' } its(:body) { should include '"access_token":"access_token"' } its(:body) { should include '"token_type":"bearer"' } [:username, :password].each do |required| context "when #{required} is missing" do before do params.delete_if do |key, value| key == required end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end end rack-oauth2-1.4.0/spec/rack/oauth2/server/token_spec.rb0000644000004100000410000000740512750322535022737 0ustar www-datawww-datarequire 'spec_helper.rb' require 'base64' describe Rack::OAuth2::Server::Token do let(:request) { Rack::MockRequest.new app } let(:app) do Rack::OAuth2::Server::Token.new do |request, response| response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token') end end let(:params) do { grant_type: 'authorization_code', client_id: 'client_id', code: 'authorization_code', redirect_uri: 'http://client.example.com/callback' } end subject { request.post('/token', params: params) } context 'when multiple client credentials are given' do context 'when different credentials are given' do let(:env) do Rack::MockRequest.env_for( '/token', 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('client_id2:client_secret')}", params: params ) end it 'should fail with unsupported_grant_type' do status, header, response = app.call(env) status.should == 400 response.body.first.should include '"error":"invalid_request"' end end context 'when same credentials are given' do let(:env) do Rack::MockRequest.env_for( '/token', 'HTTP_AUTHORIZATION' => "Basic #{Base64.encode64('client_id:client_secret')}", params: params ) end it 'should ignore duplicates' do status, header, response = app.call(env) status.should == 200 end end end context 'when unsupported grant_type is given' do before do params.merge!(grant_type: 'unknown') end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"unsupported_grant_type"' } end [:client_id, :grant_type].each do |required| context "when #{required} is missing" do before do params.delete_if do |key, value| key == required end end its(:status) { should == 400 } its(:content_type) { should == 'application/json' } its(:body) { should include '"error":"invalid_request"' } end end Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION.each do |error, default_message| status = if error == :invalid_client 401 else 400 end context "when #{error}" do let(:app) do Rack::OAuth2::Server::Token.new do |request, response| request.send "#{error}!" end end its(:status) { should == status } its(:content_type) { should == 'application/json' } its(:body) { should include "\"error\":\"#{error}\"" } its(:body) { should include "\"error_description\":\"#{default_message}\"" } end end context 'when responding' do context 'when access_token is missing' do let(:app) do Rack::OAuth2::Server::Token.new end it do expect { request.post('/', params: params) }.to raise_error AttrRequired::AttrMissing end end end describe 'extensibility' do before do require 'rack/oauth2/server/token/extension/example' end subject { app } let(:env) do Rack::MockRequest.env_for( '/token', params: params ) end let(:request) { Rack::OAuth2::Server::Token::Request.new env } its(:extensions) { should == [Rack::OAuth2::Server::Token::Extension::Example] } describe 'JWT assertion' do let(:params) do { grant_type: 'urn:ietf:params:oauth:grant-type:example', assertion: 'header.payload.signature' } end it do app.send( :grant_type_for, request ).should == Rack::OAuth2::Server::Token::Extension::Example end end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/0000755000004100000410000000000012750322535021405 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/access_token/mac/0000755000004100000410000000000012750322535022145 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/access_token/mac/sha256_hex_verifier_spec.rb0000644000004100000410000000150412750322535027253 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier do # From the example of webtopay wallet API spec # ref) https://www.webtopay.com/wallet/#authentication context 'when example from webtopay wallet API' do subject do Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier.new( algorithm: 'hmac-sha-256', raw_body: 'grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=http%3A%2F%2Flocalhost%2Fabc' ) end its(:calculate) { should == '21fb73c40b589622d0c78e9cd8900f89d9472aa724d0e5c3eca9ac1cd9d2a6d5' } end context 'when raw_body is empty' do subject do Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier.new( algorithm: 'hmac-sha-256', raw_body: '' ) end its(:calculate) { should be_nil } end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/mac/verifier_spec.rb0000644000004100000410000000131012750322535025312 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::MAC::Verifier do let(:verifier) { Rack::OAuth2::AccessToken::MAC::Verifier.new(algorithm: algorithm) } subject { verifier } context 'when "hmac-sha-1" is specified' do let(:algorithm) { 'hmac-sha-1' } its(:hash_generator) { should be_instance_of OpenSSL::Digest::SHA1 } end context 'when "hmac-sha-256" is specified' do let(:algorithm) { 'hmac-sha-256' } its(:hash_generator) { should be_instance_of OpenSSL::Digest::SHA256 } end context 'otherwise' do let(:algorithm) { 'invalid' } it do expect { verifier.send(:hash_generator) }.to raise_error(StandardError, 'Unsupported Algorithm') end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/mac/signature_spec.rb0000644000004100000410000000354212750322535025511 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::MAC::Signature do # From the example of Webtopay wallet API # ref) https://www.webtopay.com/wallet/ context 'when ext is not given' do subject do Rack::OAuth2::AccessToken::MAC::Signature.new( secret: 'IrdTc8uQodU7PRpLzzLTW6wqZAO6tAMU', algorithm: 'hmac-sha-256', nonce: 'dj83hs9s', ts: 1336363200, method: 'GET', request_uri: '/wallet/rest/api/v1/payment/123', host: 'www.webtopay.com', port: 443 ) end its(:calculate) { should == 'OZE9fTk2qiRtL1jb01L8lRxC66PTiAGhMDEmboeVeLs=' } end # From the example of MAC spec section 1.1 # ref) http://tools.ietf.org/pdf/draft-ietf-oauth-v2-http-mac-01.pdf context 'when ext is not given' do subject do Rack::OAuth2::AccessToken::MAC::Signature.new( secret: '489dks293j39', algorithm: 'hmac-sha-1', nonce: 'dj83hs9s', ts: 1336363200, method: 'GET', request_uri: '/resource/1?b=1&a=2', host: 'example.com', port: 80 ) end its(:calculate) { should == '6T3zZzy2Emppni6bzL7kdRxUWL4=' } end # From the example of MAC spec section 3.2 # ref) http://tools.ietf.org/pdf/draft-ietf-oauth-v2-http-mac-01.pdf context 'otherwise' do subject do Rack::OAuth2::AccessToken::MAC::Signature.new( secret: '489dks293j39', algorithm: 'hmac-sha-1', nonce: '7d8f3e4a', ts: 264095, method: 'POST', request_uri: '/request?b5=%3D%253D&a3=a&c%40=&a2=r%20b&c2&a3=2+q', host: 'example.com', port: 80, ext: 'a,b,c' ) end its(:calculate) { should == '+txL5oOFHGYjrfdNYH5VEzROaBY=' } end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/legacy_spec.rb0000644000004100000410000000125512750322535024213 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::Legacy do let :token do Rack::OAuth2::AccessToken::Legacy.new( access_token: 'access_token' ) end let(:resource_endpoint) { 'https://server.example.com/resources/fake' } let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {hello: "world"}, {}) } describe '#to_s' do subject { token } its(:to_s) { should == token.access_token } end describe '.authenticate' do it 'should set Authorization header' do expect(request.header).to receive(:[]=).with('Authorization', 'OAuth access_token') token.authenticate(request) end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/bearer_spec.rb0000644000004100000410000000111312750322535024200 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::Bearer do let :token do Rack::OAuth2::AccessToken::Bearer.new( access_token: 'access_token' ) end let(:resource_endpoint) { 'https://server.example.com/resources/fake' } let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {hello: "world"}, {}) } describe '.authenticate' do it 'should set Authorization header' do expect(request.header).to receive(:[]=).with('Authorization', 'Bearer access_token') token.authenticate(request) end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/mac_spec.rb0000644000004100000410000001101612750322535023503 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::MAC do let(:ts) { 1305820234 } let :token do Rack::OAuth2::AccessToken::MAC.new( access_token: 'access_token', mac_key: 'secret', mac_algorithm: 'hmac-sha-256', ts: ts ) end let :token_with_ext_verifier do Rack::OAuth2::AccessToken::MAC.new( access_token: 'access_token', mac_key: 'secret', mac_algorithm: 'hmac-sha-256', ts: ts, ext_verifier: Rack::OAuth2::AccessToken::MAC::Sha256HexVerifier ) end let(:nonce) { '1000:51e74de734c05613f37520872e68db5f' } let(:resource_endpoint) { 'https://server.example.com/resources/fake' } subject { token } its(:mac_key) { should == 'secret' } its(:mac_algorithm) { should == 'hmac-sha-256' } its(:token_response) do should == { access_token: 'access_token', refresh_token: nil, token_type: :mac, expires_in: nil, scope: '', mac_key: 'secret', mac_algorithm: 'hmac-sha-256' } end its(:generate_nonce) { should be_a String } describe 'verify!' do let(:request) { Rack::OAuth2::Server::Resource::MAC::Request.new(env) } context 'when no ext_verifier is given' do let(:env) do Rack::MockRequest.env_for( '/protected_resources', 'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", ts="#{ts}" mac="#{signature}"} ) end context 'when signature is valid' do let(:signature) { 'BgooS/voPOZWLwoVfx4+zbC3xAVKW3jtjhKYOfIGZOA=' } it do token.verify!(request.setup!).should == :verified end end context 'otherwise' do let(:signature) { 'invalid' } it do expect { token.verify!(request.setup!) }.to raise_error( Rack::OAuth2::Server::Resource::MAC::Unauthorized, 'invalid_token :: Signature Invalid' ) end end end context 'when ext_verifier is given' do let(:env) do Rack::MockRequest.env_for( '/protected_resources', method: :POST, params: { key1: 'value1' }, 'HTTP_AUTHORIZATION' => %{MAC id="access_token", nonce="#{nonce}", ts="#{ts}", mac="#{signature}", ext="#{ext}"} ) end let(:signature) { 'invalid' } context 'when ext is invalid' do let(:ext) { 'invalid' } it do expect { token_with_ext_verifier.verify!(request.setup!) }.to raise_error( Rack::OAuth2::Server::Resource::MAC::Unauthorized, 'invalid_token :: Sha256HexVerifier Invalid' ) end end context 'when ext is valid' do let(:ext) { '4cfcd46c59f54b5ea6a5f9b05c28b52fef2864747194b5fdfc3d59c0057bf35a' } context 'when signature is valid' do let(:signature) { 'dZYR54n+Lym5qCRRmDqmRZ71rG+bkjSWmqrOv8OjYHk=' } it do Time.fix(Time.at(1302361200)) do token_with_ext_verifier.verify!(request.setup!).should == :verified end end end context 'otherwise' do it do expect { token.verify!(request.setup!) }.to raise_error( Rack::OAuth2::Server::Resource::MAC::Unauthorized, 'invalid_token :: Signature Invalid' ) end end end end end describe '.authenticate' do let(:request) { HTTPClient.new.send(:create_request, :post, URI.parse(resource_endpoint), {}, {hello: "world"}, {}) } context 'when no ext_verifier is given' do let(:signature) { 'pOBaL6HRawe4tUPmcU4vJEj1f2GJqrbQOlCcdAYgI/s=' } it 'should set Authorization header' do expect(token).to receive(:generate_nonce).and_return(nonce) expect(request.header).to receive(:[]=).with('Authorization', "MAC id=\"access_token\", nonce=\"#{nonce}\", ts=\"#{ts.to_i}\", mac=\"#{signature}\"") token.authenticate(request) end end context 'when ext_verifier is given' do let(:signature) { 'vgU0fj6rSpwUCAoCOrXlu8pZBR8a5Q5xIVlB4MCvJeM=' } let(:ext) { '3d011e09502a84552a0f8ae112d024cc2c115597e3a577d5f49007902c221dc5' } it 'should set Authorization header with ext_verifier' do expect(token_with_ext_verifier).to receive(:generate_nonce).and_return(nonce) expect(request.header).to receive(:[]=).with('Authorization', "MAC id=\"access_token\", nonce=\"#{nonce}\", ts=\"#{ts.to_i}\", mac=\"#{signature}\", ext=\"#{ext}\"") token_with_ext_verifier.authenticate(request) end end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token/authenticator_spec.rb0000644000004100000410000000225212750322535025617 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken::Authenticator do let(:resource_endpoint) { 'https://server.example.com/resources/fake' } let(:request) { HTTP::Message.new_request(:get, URI.parse(resource_endpoint)) } let(:authenticator) { Rack::OAuth2::AccessToken::Authenticator.new(token) } shared_examples_for :authenticator do it 'should let the token authenticate the request' do expect(token).to receive(:authenticate).with(request) authenticator.filter_request(request) end end context 'when Legacy token is given' do let(:token) do Rack::OAuth2::AccessToken::Legacy.new( access_token: 'access_token' ) end it_behaves_like :authenticator end context 'when Bearer token is given' do let(:token) do Rack::OAuth2::AccessToken::Bearer.new( access_token: 'access_token' ) end it_behaves_like :authenticator end context 'when MAC token is given' do let(:token) do Rack::OAuth2::AccessToken::MAC.new( access_token: 'access_token', mac_key: 'secret', mac_algorithm: 'hmac-sha-256' ) end it_behaves_like :authenticator end end rack-oauth2-1.4.0/spec/rack/oauth2/client/0000755000004100000410000000000012750322535020222 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/client/grant/0000755000004100000410000000000012750322535021335 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/client/grant/client_credentials_spec.rb0000644000004100000410000000024212750322535026525 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::ClientCredentials do its(:as_json) do should == {grant_type: :client_credentials} end end rack-oauth2-1.4.0/spec/rack/oauth2/client/grant/authorization_code_spec.rb0000644000004100000410000000177512750322535026600 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::AuthorizationCode do let(:redirect_uri) { 'https://client.example.com/callback' } let(:grant) { Rack::OAuth2::Client::Grant::AuthorizationCode } context 'when code is given' do let :attributes do {code: 'code'} end context 'when redirect_uri is given' do let :attributes do {code: 'code', redirect_uri: redirect_uri} end subject { grant.new attributes } its(:redirect_uri) { should == redirect_uri } its(:as_json) do should == {grant_type: :authorization_code, code: 'code', redirect_uri: redirect_uri} end end context 'otherwise' do subject { grant.new attributes } its(:redirect_uri) { should be_nil } its(:as_json) do should == {grant_type: :authorization_code, code: 'code', redirect_uri: nil} end end end context 'otherwise' do it do expect { grant.new }.to raise_error AttrRequired::AttrMissing end end end rack-oauth2-1.4.0/spec/rack/oauth2/client/grant/refresh_token_spec.rb0000644000004100000410000000101512750322535025527 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::RefreshToken do let(:grant) { Rack::OAuth2::Client::Grant::RefreshToken } context 'when refresh_token is given' do let :attributes do {refresh_token: 'refresh_token'} end subject { grant.new attributes } its(:as_json) do should == {grant_type: :refresh_token, refresh_token: 'refresh_token'} end end context 'otherwise' do it do expect { grant.new }.to raise_error AttrRequired::AttrMissing end end end rack-oauth2-1.4.0/spec/rack/oauth2/client/grant/saml2_bearer_spec.rb0000644000004100000410000000104612750322535025233 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::SAML2Bearer do let(:grant) { Rack::OAuth2::Client::Grant::SAML2Bearer } context 'when JWT assertion is given' do let :attributes do {assertion: '...'} end subject { grant.new attributes } its(:as_json) do should == {grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', assertion: '...'} end end context 'otherwise' do it do expect { grant.new }.to raise_error AttrRequired::AttrMissing end end end rack-oauth2-1.4.0/spec/rack/oauth2/client/grant/jwt_bearer_spec.rb0000644000004100000410000000106412750322535025021 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::JWTBearer do let(:grant) { Rack::OAuth2::Client::Grant::JWTBearer } context 'when JWT assertion is given' do let :attributes do {assertion: 'header.payload.signature'} end subject { grant.new attributes } its(:as_json) do should == {grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: 'header.payload.signature'} end end context 'otherwise' do it do expect { grant.new }.to raise_error AttrRequired::AttrMissing end end end rack-oauth2-1.4.0/spec/rack/oauth2/client/grant/password_spec.rb0000644000004100000410000000143112750322535024535 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Grant::Password do let(:grant) { Rack::OAuth2::Client::Grant::Password } context 'when username is given' do let :attributes do {username: 'username'} end context 'when password is given' do let :attributes do {username: 'username', password: 'password'} end subject { grant.new attributes } its(:as_json) do should == {grant_type: :password, username: 'username', password: 'password'} end end context 'otherwise' do it do expect { grant.new attributes }.to raise_error AttrRequired::AttrMissing end end end context 'otherwise' do it do expect { grant.new }.to raise_error AttrRequired::AttrMissing end end end rack-oauth2-1.4.0/spec/rack/oauth2/client/error_spec.rb0000644000004100000410000000070512750322535022714 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client::Error do let :error do { error: :invalid_request, error_description: 'Include invalid parameters', error_uri: 'http://server.example.com/error/invalid_request' } end subject do Rack::OAuth2::Client::Error.new 400, error end its(:status) { should == 400 } its(:message) { should == error[:error_description] } its(:response) { should == error } end rack-oauth2-1.4.0/spec/rack/oauth2/debugger/0000755000004100000410000000000012750322535020530 5ustar www-datawww-datarack-oauth2-1.4.0/spec/rack/oauth2/debugger/request_filter_spec.rb0000644000004100000410000000207112750322535025124 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::Debugger::RequestFilter do let(:resource_endpoint) { 'https://example.com/resources' } let(:request) { HTTP::Message.new_request(:get, URI.parse(resource_endpoint)) } let(:response) { HTTP::Message.new_response(MultiJson.dump({hello: 'world'})) } let(:request_filter) { Rack::OAuth2::Debugger::RequestFilter.new } describe '#filter_request' do it 'should log request' do [ "======= [Rack::OAuth2] HTTP REQUEST STARTED =======", request.dump ].each do |output| expect(Rack::OAuth2.logger).to receive(:info).with output end request_filter.filter_request(request) end end describe '#filter_response' do it 'should log response' do [ "--------------------------------------------------", response.dump, "======= [Rack::OAuth2] HTTP REQUEST FINISHED =======" ].each do |output| expect(Rack::OAuth2.logger).to receive(:info).with output end request_filter.filter_response(request, response) end end end rack-oauth2-1.4.0/spec/rack/oauth2/client_spec.rb0000644000004100000410000002310612750322535021563 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Client do let :client do Rack::OAuth2::Client.new( identifier: 'client_id', secret: 'client_secret', host: 'server.example.com', redirect_uri: 'https://client.example.com/callback' ) end subject { client } its(:identifier) { should == 'client_id' } its(:secret) { should == 'client_secret' } its(:authorization_endpoint) { should == '/oauth2/authorize' } its(:token_endpoint) { should == '/oauth2/token' } context 'when identifier is missing' do it do expect { Rack::OAuth2::Client.new }.to raise_error AttrRequired::AttrMissing end end describe '#authorization_uri' do subject { client.authorization_uri } it { should include 'https://server.example.com/oauth2/authorize' } it { should include 'client_id=client_id' } it { should include 'redirect_uri=https%3A%2F%2Fclient.example.com%2Fcallback' } it { should include 'response_type=code' } context 'when endpoints are absolute URIs' do before do client.authorization_endpoint = 'https://server2.example.com/oauth/authorize' client.token_endpoint = 'https://server2.example.com/oauth/token' end it { should include 'https://server2.example.com/oauth/authorize' } end context 'when scheme is specified' do before { client.scheme = 'http' } it { should include 'http://server.example.com/oauth2/authorize' } end context 'when response_type is token' do subject { client.authorization_uri(response_type: :token) } it { should include 'response_type=token' } end context 'when response_type is an Array' do subject { client.authorization_uri(response_type: [:token, :code]) } it { should include 'response_type=token+code' } end context 'when scope is given' do subject { client.authorization_uri(scope: [:scope1, :scope2]) } it { should include 'scope=scope1+scope2' } end end describe '#authorization_code=' do before { client.authorization_code = 'code' } subject { client.instance_variable_get('@grant') } it { should be_instance_of Rack::OAuth2::Client::Grant::AuthorizationCode } end describe '#resource_owner_credentials=' do before { client.resource_owner_credentials = 'username', 'password' } subject { client.instance_variable_get('@grant') } it { should be_instance_of Rack::OAuth2::Client::Grant::Password } end describe '#refresh_token=' do before { client.refresh_token = 'refresh_token' } subject { client.instance_variable_get('@grant') } it { should be_instance_of Rack::OAuth2::Client::Grant::RefreshToken } end describe '#access_token!' do subject { client.access_token! } context 'when *args given' do describe 'client authentication method' do before do client.authorization_code = 'code' end it 'should be Basic auth as default' do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json', request_header: { 'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=' } ) client.access_token! end context 'when other auth method specified' do it 'should be body params' do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json', params: { client_id: 'client_id', client_secret: 'client_secret', code: 'code', grant_type: 'authorization_code', redirect_uri: 'https://client.example.com/callback' } ) client.access_token! :client_auth_body end end context 'when auth method is specified as Hash' do it 'should be removed before sending request' do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json', params: { client_id: 'client_id', client_secret: 'client_secret', code: 'code', grant_type: 'authorization_code', redirect_uri: 'https://client.example.com/callback' } ) client.access_token! client_auth_method: :body end end end describe 'scopes' do context 'when scope option given' do it 'should specify given scope' do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json', params: { grant_type: 'client_credentials', scope: 'a b' } ) client.access_token! scope: [:a, :b] end end end describe 'unknown params' do it 'should be included in body params' do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json', params: { grant_type: 'client_credentials', resource: 'something' } ) client.access_token! resource: :something end end end context 'when bearer token is given' do before do client.authorization_code = 'code' mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/bearer.json' ) end it { should be_instance_of Rack::OAuth2::AccessToken::Bearer } its(:token_type) { should == :bearer } its(:access_token) { should == 'access_token' } its(:refresh_token) { should == 'refresh_token' } its(:expires_in) { should == 3600 } context 'when token type is "Bearer", not "bearer"' do before do client.authorization_code = 'code' mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/_Bearer.json' ) end it { should be_instance_of Rack::OAuth2::AccessToken::Bearer } its(:token_type) { should == :bearer } end end context 'when mac token is given' do before do client.authorization_code = 'code' mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/mac.json' ) end it { should be_instance_of Rack::OAuth2::AccessToken::MAC } its(:token_type) { should == :mac } its(:access_token) { should == 'access_token' } its(:refresh_token) { should == 'refresh_token' } its(:expires_in) { should == 3600 } end context 'when no-type token is given (JSON)' do before do client.authorization_code = 'code' mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/legacy.json' ) end it { should be_instance_of Rack::OAuth2::AccessToken::Legacy } its(:token_type) { should == :legacy } its(:access_token) { should == 'access_token' } its(:refresh_token) { should == 'refresh_token' } its(:expires_in) { should == 3600 } end context 'when no-type token is given (key-value)' do before do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/legacy.txt' ) end it { should be_instance_of Rack::OAuth2::AccessToken::Legacy } its(:token_type) { should == :legacy } its(:access_token) { should == 'access_token' } its(:expires_in) { should == 3600 } context 'when expires_in is not given' do before do mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/legacy_without_expires_in.txt' ) end its(:expires_in) { should be_nil } end end context 'when unknown-type token is given' do before do client.authorization_code = 'code' mock_response( :post, 'https://server.example.com/oauth2/token', 'tokens/unknown.json' ) end it do expect { client.access_token! }.to raise_error(StandardError, 'Unknown Token Type') end end context 'when error response is given' do before do mock_response( :post, 'https://server.example.com/oauth2/token', 'errors/invalid_request.json', status: 400 ) end it do expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error end end context 'when no body given' do context 'when error given' do before do mock_response( :post, 'https://server.example.com/oauth2/token', 'blank', status: 400 ) end it do expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error end end end end context 'when no host info' do let :client do Rack::OAuth2::Client.new( identifier: 'client_id', secret: 'client_secret', redirect_uri: 'https://client.example.com/callback' ) end describe '#authorization_uri' do it do expect { client.authorization_uri }.to raise_error 'No Host Info' end end describe '#access_token!' do it do expect { client.access_token! }.to raise_error 'No Host Info' end end end end rack-oauth2-1.4.0/spec/rack/oauth2/util_spec.rb0000644000004100000410000000465112750322535021266 0ustar www-datawww-datarequire 'spec_helper.rb' describe Rack::OAuth2::Util do let :util do Rack::OAuth2::Util end let :uri do 'http://client.example.com/callback' end describe '.rfc3986_encode' do subject { util.rfc3986_encode '=+ .-/' } it { should == '%3D%2B%20.-%2F' } end describe '.base64_encode' do subject { util.base64_encode '=+ .-/' } it { should == 'PSsgLi0v' } end describe '.compact_hash' do subject { util.compact_hash k1: 'v1', k2: '', k3: nil } it { should == {k1: 'v1'} } end describe '.parse_uri' do context 'when String is given' do it { util.parse_uri(uri).should be_a URI::Generic } end context 'when URI is given' do it 'should be itself' do _uri_ = URI.parse uri util.parse_uri(_uri_).should be _uri_ end end context 'when invalid URI is given' do it do expect do util.parse_uri '::' end.to raise_error URI::InvalidURIError end end context 'otherwise' do it do expect { util.parse_uri nil }.to raise_error StandardError expect { util.parse_uri 123 }.to raise_error StandardError end end end describe '.redirect_uri' do let(:base_uri) { 'http://client.example.com' } let(:params) do {k1: :v1, k2: ''} end subject { util.redirect_uri base_uri, location, params } context 'when location = :fragment' do let(:location) { :fragment } it { should == "#{base_uri}##{util.compact_hash(params).to_query}" } end context 'when location = :query' do let(:location) { :query } it { should == "#{base_uri}?#{util.compact_hash(params).to_query}" } end end describe '.uri_match?' do context 'when invalid URI is given' do it do util.uri_match?('::', '::').should == false util.uri_match?(123, 'http://client.example.com/other').should == false util.uri_match?('http://client.example.com/other', nil).should == false end end context 'when exactly same' do it { util.uri_match?(uri, uri).should == true } end context 'when path prefix matches' do it { util.uri_match?(uri, "#{uri}/deep_path").should == true } end context 'otherwise' do it do util.uri_match?(uri, 'http://client.example.com/other').should == false util.uri_match?(uri, 'http://attacker.example.com/callback').should == false end end end end rack-oauth2-1.4.0/spec/rack/oauth2/access_token_spec.rb0000644000004100000410000000423412750322535022747 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2::AccessToken do let :token do Rack::OAuth2::AccessToken::Bearer.new( access_token: 'access_token', refresh_token: 'refresh_token', expires_in: 3600, scope: [:scope1, :scope2] ) end subject { token } its(:access_token) { should == 'access_token' } its(:refresh_token) { should == 'refresh_token' } its(:expires_in) { should == 3600 } its(:scope) { should == [:scope1, :scope2] } its(:token_response) do should == { token_type: :bearer, access_token: 'access_token', refresh_token: 'refresh_token', expires_in: 3600, scope: 'scope1 scope2' } end context 'when access_token is missing' do it do expect do Rack::OAuth2::AccessToken::Bearer.new( refresh_token: 'refresh_token', expires_in: 3600, scope: [:scope1, :scope2] ) end.to raise_error AttrRequired::AttrMissing end end context 'otherwise' do it do expect do Rack::OAuth2::AccessToken::Bearer.new( access_token: 'access_token' ) end.not_to raise_error end end let(:resource_endpoint) { 'https://server.example.com/resources/fake' } [:get, :delete, :post, :put].each do |method| describe method do it 'should delegate to HTTPClient with Authenticator filter' do expect(token.httpclient).to receive(method).with(resource_endpoint) token.httpclient.request_filter.last.should be_a Rack::OAuth2::AccessToken::Authenticator token.send method, resource_endpoint end end context 'in debug mode' do it do Rack::OAuth2.debug do token.httpclient.request_filter[-2].should be_a Rack::OAuth2::AccessToken::Authenticator token.httpclient.request_filter.last.should be_a Rack::OAuth2::Debugger::RequestFilter end end end context 'when extension params given' do subject do Rack::OAuth2::AccessToken::Bearer.new( access_token: 'access_token', ex_key: :ex_value ) end its(:raw_attributes) { should include :ex_key } end end end rack-oauth2-1.4.0/spec/rack/oauth2/oauth2_spec.rb0000644000004100000410000000413012750322535021503 0ustar www-datawww-datarequire 'spec_helper' describe Rack::OAuth2 do subject { Rack::OAuth2 } after { Rack::OAuth2.debugging = false } its(:logger) { should be_a Logger } its(:debugging?) { should == false } describe '.debug!' do before { Rack::OAuth2.debug! } its(:debugging?) { should == true } end describe '.debug' do it 'should enable debugging within given block' do Rack::OAuth2.debug do Rack::OAuth2.debugging?.should == true end Rack::OAuth2.debugging?.should == false end it 'should not force disable debugging' do Rack::OAuth2.debug! Rack::OAuth2.debug do Rack::OAuth2.debugging?.should == true end Rack::OAuth2.debugging?.should == true end end describe '.http_config' do context 'when request_filter added' do context 'when "debug!" is called' do after { Rack::OAuth2.reset_http_config! } it 'should put Debugger::RequestFilter at last' do Rack::OAuth2.debug! Rack::OAuth2.http_config do |config| config.request_filter << Proc.new {} end Rack::OAuth2.http_client.request_filter.last.should be_instance_of Rack::OAuth2::Debugger::RequestFilter end it 'should reset_http_config' do Rack::OAuth2.debug! Rack::OAuth2.http_config do |config| config.request_filter << Proc.new {} end size = Rack::OAuth2.http_client.request_filter.size Rack::OAuth2.reset_http_config! Rack::OAuth2.http_client.request_filter.size.should == size - 1 end end end end describe ".http_client" do context "when local_http_config is used" do it "should correctly set request_filter" do clnt1 = Rack::OAuth2.http_client clnt2 = Rack::OAuth2.http_client("my client") do |config| config.request_filter << Proc.new {} end clnt3 = Rack::OAuth2.http_client clnt1.request_filter.size.should == clnt3.request_filter.size clnt1.request_filter.size.should == clnt2.request_filter.size - 1 end end end endrack-oauth2-1.4.0/README.rdoc0000644000004100000410000000410612750322535015477 0ustar www-datawww-data= rack-oauth2 OAuth 2.0 Server & Client Library. Both Bearer and MAC token type are supported. {}[http://travis-ci.org/nov/rack-oauth2] The OAuth 2.0 Authorization Framework (RFC 6749) http://www.rfc-editor.org/rfc/rfc6749.txt The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750) http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-06 HTTP Authentication: MAC Access Authentication (draft 01) http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 == Installation gem install rack-oauth2 == Resources * View Source on GitHub (https://github.com/nov/rack-oauth2) * Docs on GitHub (https://github.com/nov/rack-oauth2/wiki) * Report Issues on GitHub (https://github.com/nov/rack-oauth2/issues) == Sample Server Application (Rails3) === Bearer Running on Heroku https://rack-oauth2-sample.heroku.com Source on GitHub https://github.com/nov/rack-oauth2-sample === MAC Running on Heroku https://rack-oauth2-sample-mac.heroku.com Source on GitHub https://github.com/nov/rack-oauth2-sample-mac == Sample Client === Common between Bearer and MAC Authorization Request (request_type: 'code' and 'token') https://gist.github.com/862393 Token Request (grant_type: 'client_credentials', 'password', 'authorization_code' and 'refresh_token') https://gist.github.com/883541 === Bearer Resource Request (request both for resource owner resource and for client resource) https://gist.github.com/883575 === MAC Resource Request (request both for resource owner resource and for client resource) https://gist.github.com/933885 == Note on Patches/Pull Requests * Fork the project. * Make your feature addition or bug fix. * Add tests for it. This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) * Send me a pull request. Bonus points for topic branches. == Copyright Copyright (c) 2010 nov matake. See LICENSE for details. rack-oauth2-1.4.0/.travis.yml0000644000004100000410000000011312750322535015774 0ustar www-datawww-databefore_install: - gem install bundler rvm: - 2.2.2 - 2.2.5 - 2.3.1rack-oauth2-1.4.0/lib/0000755000004100000410000000000012750322535014436 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/0000755000004100000410000000000012750322535015356 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/0000755000004100000410000000000012750322535016560 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/debugger.rb0000644000004100000410000000012012750322535020662 0ustar www-datawww-dataDir[File.dirname(__FILE__) + '/debugger/*.rb'].each do |file| require file endrack-oauth2-1.4.0/lib/rack/oauth2/server/0000755000004100000410000000000012750322535020066 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/0000755000004100000410000000000012750322535022100 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/code.rb0000644000004100000410000000156412750322535023345 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize class Code < Abstract::Handler def call(env) @request = Request.new env @response = Response.new request super end class Request < Authorize::Request include Server::Extension::PKCE::AuthorizationRequest def initialize(env) super @response_type = :code attr_missing! end def error_params_location :query end end class Response < Authorize::Response attr_required :code def protocol_params super.merge(code: code) end def protocol_params_location :query end end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/extension.rb0000644000004100000410000000042712750322535024444 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize module Extension # Define your extension in this namespace and load it explicitly. # extension/code_and_token.rb would be good example for you. end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/extension/0000755000004100000410000000000012750322535024114 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/extension/code_and_token.rb0000644000004100000410000000176712750322535027410 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize module Extension class CodeAndToken < Abstract::Handler class << self def response_type_for?(response_type) response_type.split.sort == ['code', 'token'] end end def call(env) @request = Request.new env @response = Response.new request super end class Request < Authorize::Token::Request include Server::Extension::PKCE::AuthorizationRequest def initialize(env) super @response_type = [:code, :token] attr_missing! end end class Response < Authorize::Token::Response attr_required :code def protocol_params super.merge(code: code) end end end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/token.rb0000644000004100000410000000167712750322535023560 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize class Token < Abstract::Handler def call(env) @request = Request.new env @response = Response.new request super end class Request < Authorize::Request def initialize(env) super @response_type = :token attr_missing! end def error_params_location :fragment end end class Response < Authorize::Response attr_required :access_token def protocol_params super.merge( access_token.token_response.delete_if do |k, v| k == :refresh_token end ) end def protocol_params_location :fragment end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/authorize/error.rb0000644000004100000410000000631512750322535023563 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize module ErrorHandler def self.included(klass) klass.send :attr_accessor, :redirect_uri, :state, :protocol_params_location end def protocol_params super.merge(state: state) end def redirect? redirect_uri.present? && protocol_params_location.present? end def finish if redirect? super do |response| response.redirect Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params) end else raise self end end end class BadRequest < Abstract::BadRequest include ErrorHandler end class ServerError < Abstract::ServerError include ErrorHandler end class TemporarilyUnavailable < Abstract::TemporarilyUnavailable include ErrorHandler end module ErrorMethods DEFAULT_DESCRIPTION = { invalid_request: "The request is missing a required parameter, includes an unsupported parameter or parameter value, or is otherwise malformed.", unauthorized_client: "The client is not authorized to use the requested response type.", access_denied: "The end-user or authorization server denied the request.", unsupported_response_type: "The requested response type is not supported by the authorization server.", invalid_scope: "The requested scope is invalid, unknown, or malformed.", server_error: "Internal Server Error", temporarily_unavailable: "Service Unavailable" } def self.included(klass) DEFAULT_DESCRIPTION.each do |error, default_description| case error when :server_error, :temporarily_unavailable # NOTE: defined below else klass.class_eval <<-ERROR def #{error}!(description = "#{default_description}", options = {}) bad_request! :#{error}, description, options end ERROR end end end def bad_request!(error = :bad_request, description = nil, options = {}) error! BadRequest, error, description, options end def server_error!(description = DEFAULT_DESCRIPTION[:server_error], options = {}) error! ServerError, :server_error, description, options end def temporarily_unavailable!(description = DEFAULT_DESCRIPTION[:temporarily_unavailable], options = {}) error! TemporarilyUnavailable, :temporarily_unavailable, description, options end private def error!(klass, error, description, options) exception = klass.new error, description, options exception.protocol_params_location = error_params_location exception.state = state exception.redirect_uri = verified_redirect_uri raise exception end end Request.send :include, ErrorMethods end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/resource/0000755000004100000410000000000012750322535021715 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/resource/mac/0000755000004100000410000000000012750322535022455 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/resource/mac/error.rb0000644000004100000410000000103712750322535024134 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource class MAC class Unauthorized < Resource::Unauthorized def scheme :MAC end end module ErrorMethods include Resource::ErrorMethods def unauthorized!(error = nil, description = nil, options = {}) raise Unauthorized.new(error, description, options) end end Request.send :include, ErrorMethods end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/resource/bearer/0000755000004100000410000000000012750322535023155 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/resource/bearer/error.rb0000644000004100000410000000104512750322535024633 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource class Bearer class Unauthorized < Resource::Unauthorized def scheme :Bearer end end module ErrorMethods include Resource::ErrorMethods def unauthorized!(error = nil, description = nil, options = {}) raise Unauthorized.new(error, description, options) end end Request.send :include, ErrorMethods end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/resource/bearer.rb0000644000004100000410000000230312750322535023500 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource class Bearer < Resource def call(env) self.request = Request.new(env) super end private class Request < Resource::Request def setup! tokens = [access_token_in_header, access_token_in_payload].compact @access_token = case Array(tokens).size when 1 tokens.first else invalid_request!('Both Authorization header and payload includes access token.') end self end def oauth2? (access_token_in_header || access_token_in_payload).present? end def access_token_in_header if @auth_header.provided? && !@auth_header.parts.first.nil? && @auth_header.scheme.to_s == 'bearer' @auth_header.params else nil end end def access_token_in_payload params['access_token'] end end end end end end end require 'rack/oauth2/server/resource/bearer/error' rack-oauth2-1.4.0/lib/rack/oauth2/server/resource/mac.rb0000644000004100000410000000161412750322535023004 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource class MAC < Resource def call(env) self.request = Request.new(env) super end private class Request < Resource::Request attr_reader :nonce, :ts, :ext, :signature def setup! auth_params = Rack::Auth::Digest::Params.parse(@auth_header.params).with_indifferent_access @access_token = auth_params[:id] @nonce = auth_params[:nonce] @ts = auth_params[:ts] @ext = auth_params[:ext] @signature = auth_params[:mac] self end def oauth2? @auth_header.provided? && @auth_header.scheme.to_s == 'mac' end end end end end end end require 'rack/oauth2/server/resource/mac/error' rack-oauth2-1.4.0/lib/rack/oauth2/server/resource/error.rb0000644000004100000410000000531712750322535023401 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource class BadRequest < Abstract::BadRequest end class Unauthorized < Abstract::Unauthorized def scheme raise 'Define me!' end def finish super do |response| self.realm ||= DEFAULT_REALM header = response.header['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\"" if ErrorMethods::DEFAULT_DESCRIPTION.keys.include?(error) header << ", error=\"#{error}\"" header << ", error_description=\"#{description}\"" if description.present? header << ", error_uri=\"#{uri}\"" if uri.present? end end end end class Forbidden < Abstract::Forbidden attr_accessor :scope def initialize(error = :forbidden, description = nil, options = {}) super @scope = options[:scope] end def protocol_params super.merge(scope: Array(scope).join(' ')) end end module ErrorMethods DEFAULT_DESCRIPTION = { invalid_request: "The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed.", invalid_token: "The access token provided is expired, revoked, malformed or invalid for other reasons.", insufficient_scope: "The request requires higher privileges than provided by the access token." } def self.included(klass) DEFAULT_DESCRIPTION.each do |error, default_description| error_method = case error when :invalid_request :bad_request! when :insufficient_scope :forbidden! else :unauthorized! end klass.class_eval <<-ERROR def #{error}!(description = "#{default_description}", options = {}) #{error_method} :#{error}, description, options end ERROR end end def bad_request!(error, description = nil, options = {}) raise BadRequest.new(error, description, options) end def unauthorized!(error = nil, description = nil, options = {}) raise 'Define me!' end def forbidden!(error, description = nil, options = {}) raise Forbidden.new(error, description, options) end end Request.send :include, ErrorMethods end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/abstract/0000755000004100000410000000000012750322535021671 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/abstract/response.rb0000644000004100000410000000042012750322535024050 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Abstract class Response < Rack::Response include AttrRequired, AttrOptional def initialize(request) super([], 200, {}) end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/abstract/request.rb0000644000004100000410000000142712750322535023712 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Abstract class Request < Rack::Request include AttrRequired, AttrOptional attr_required :client_id attr_optional :scope def initialize(env) super @client_id ||= params['client_id'] @scope = Array(params['scope'].to_s.split(' ')) end def attr_missing! if params['client_id'].present? && @client_id != params['client_id'] invalid_request! 'Multiple client credentials are provided.' end super rescue AttrRequired::AttrMissing => e invalid_request! e.message, state: @state, redirect_uri: @redirect_uri end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/abstract/handler.rb0000644000004100000410000000064412750322535023637 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Abstract class Handler attr_accessor :authenticator, :request, :response def initialize(&authenticator) @authenticator = authenticator end def call(env) @authenticator.call(@request, @response) if @authenticator @response end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/abstract/error.rb0000644000004100000410000000406112750322535023350 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Abstract class Error < StandardError attr_accessor :status, :error, :description, :uri, :realm def initialize(status, error, description = nil, options = {}) @status = status @error = error @description = description @uri = options[:uri] @realm = options[:realm] super [error, description].compact.join(' :: ') end def protocol_params { error: error, error_description: description, error_uri: uri } end def finish response = Rack::Response.new response.status = status yield response if block_given? unless response.redirect? response.header['Content-Type'] = 'application/json' response.write MultiJson.dump(Util.compact_hash(protocol_params)) end response.finish end end class BadRequest < Error def initialize(error = :bad_request, description = nil, options = {}) super 400, error, description, options end end class Unauthorized < Error def initialize(error = :unauthorized, description = nil, options = {}) super 401, error, description, options end end class Forbidden < Error def initialize(error = :forbidden, description = nil, options = {}) super 403, error, description, options end end class ServerError < Error def initialize(error = :forbidden, description = nil, options = {}) super 500, error, description, options end end class TemporarilyUnavailable < Error def initialize(error = :forbidden, description = nil, options = {}) super 503, error, description, options end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/resource.rb0000644000004100000410000000242412750322535022244 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Resource < Abstract::Handler ACCESS_TOKEN = 'rack.oauth2.access_token' DEFAULT_REALM = 'Protected by OAuth 2.0' attr_accessor :realm, :request def initialize(app, realm = nil, &authenticator) @app = app @realm = realm super(&authenticator) end def call(env) if request.oauth2? access_token = authenticate! request.setup! env[ACCESS_TOKEN] = access_token end @app.call(env) rescue Rack::OAuth2::Server::Abstract::Error => e e.realm ||= realm e.finish end private def authenticate!(request) @authenticator.call(request) end class Request < Rack::Request attr_reader :access_token def initialize(env) @env = env @auth_header = Rack::Auth::AbstractRequest.new(env) end def setup! raise 'Define me!' end def oauth2? raise 'Define me!' end end end end end end require 'rack/oauth2/server/resource/error' require 'rack/oauth2/server/resource/bearer' require 'rack/oauth2/server/resource/mac' rack-oauth2-1.4.0/lib/rack/oauth2/server/authorize.rb0000644000004100000410000000651512750322535022434 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Authorize < Abstract::Handler def call(env) request = Request.new(env) response_type_for(request).new(&@authenticator).call(env).finish rescue Rack::OAuth2::Server::Abstract::Error => e e.finish end private def response_type_for(request) response_type = request.params['response_type'].to_s case response_type when 'code' Code when 'token' Token when '' request.attr_missing! else extensions.detect do |extension| extension.response_type_for? response_type end || request.unsupported_response_type! end end def extensions Extension.constants.sort.collect do |key| Extension.const_get key end end class Request < Abstract::Request attr_required :response_type attr_optional :redirect_uri, :state attr_accessor :verified_redirect_uri def initialize(env) super # NOTE: Raise before redirect_uri is saved not to redirect back to unverified redirect_uri. bad_request! if client_id.blank? @redirect_uri = Util.parse_uri(params['redirect_uri']) if params['redirect_uri'] @state = params['state'] end def verify_redirect_uri!(pre_registered, allow_partial_match = false) @verified_redirect_uri = if redirect_uri.present? verified = Array(pre_registered).any? do |_pre_registered_| if allow_partial_match Util.uri_match?(_pre_registered_, redirect_uri) else _pre_registered_.to_s == redirect_uri.to_s end end if verified redirect_uri else bad_request! end elsif pre_registered.present? && Array(pre_registered).size == 1 && !allow_partial_match Array(pre_registered).first else bad_request! end self.verified_redirect_uri.to_s end def error_params_location nil # => All errors are raised immediately and no error response are returned to client. end end class Response < Abstract::Response attr_required :redirect_uri attr_optional :state, :approval def initialize(request) @state = request.state super end def approved? @approval end def approve! @approval = true end def protocol_params {state: state} end def redirect_uri_with_credentials Util.redirect_uri(redirect_uri, protocol_params_location, protocol_params) end def finish if approved? attr_missing! redirect redirect_uri_with_credentials end super end end end end end end require 'rack/oauth2/server/authorize/code' require 'rack/oauth2/server/authorize/token' require 'rack/oauth2/server/authorize/extension' require 'rack/oauth2/server/authorize/error' rack-oauth2-1.4.0/lib/rack/oauth2/server/rails/0000755000004100000410000000000012750322535021200 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/rails/authorize.rb0000644000004100000410000000202612750322535023537 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Rails class Authorize < Server::Authorize def initialize(app) super() @app = app end def call(env) prepare_oauth_env env @app.call env rescue Rack::OAuth2::Server::Abstract::Error => e e.finish end private def prepare_oauth_env(env) response_type = response_type_for( Server::Authorize::Request.new(env) ).new response_type.call(env) response_type.response.extend ResponseExt env[REQUEST] = response_type.request env[RESPONSE] = response_type.response rescue Rack::OAuth2::Server::Abstract::Error => e env[ERROR] = e end module ResponseExt include Rails::ResponseExt def approve! super finish end end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/rails/response_ext.rb0000644000004100000410000000152712750322535024250 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Rails module ResponseExt def redirect? ensure_finish do @response.redirect? end end def location ensure_finish do super end end def json ensure_finish do @response.body end end def header ensure_finish do @header end end def finish @finished = true super end private def finished? !!@finished end def ensure_finish @status, @header, @response = finish unless finished? yield end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/extension.rb0000644000004100000410000000005312750322535022425 0ustar www-datawww-datarequire 'rack/oauth2/server/extension/pkce'rack-oauth2-1.4.0/lib/rack/oauth2/server/extension/0000755000004100000410000000000012750322535022102 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/extension/pkce.rb0000644000004100000410000000257212750322535023357 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Extension module PKCE module AuthorizationRequest def self.included(klass) klass.send :attr_optional, :code_challenge, :code_challenge_method end def initialize(env) super @code_challenge = params['code_challenge'] @code_challenge_method = params['code_challenge_method'] end end module TokenRequest def self.included(klass) klass.send :attr_optional, :code_verifier end def initialize(env) super @code_verifier = params['code_verifier'] end def verify_code_verifier!(code_challenge, code_challenge_method = :S256) if code_verifier.present? || code_challenge.present? case code_challenge_method.try(:to_sym) when :S256 code_challenge == Util.urlsafe_base64_encode( OpenSSL::Digest::SHA256.digest(code_verifier.to_s) ) or invalid_grant! when :plain code_challenge == code_verifier or invalid_grant! else invalid_grant! end end end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token.rb0000644000004100000410000000501512750322535021534 0ustar www-datawww-datarequire 'rack/auth/basic' module Rack module OAuth2 module Server class Token < Abstract::Handler def call(env) request = Request.new(env) grant_type_for(request).new(&@authenticator).call(env).finish rescue Rack::OAuth2::Server::Abstract::Error => e e.finish end private def grant_type_for(request) case request.grant_type when 'authorization_code' AuthorizationCode when 'password' Password when 'client_credentials' ClientCredentials when 'refresh_token' RefreshToken when URN::GrantType::JWT_BEARER JWTBearer when URN::GrantType::SAML2_BEARER SAML2Bearer when '' request.attr_missing! else extensions.detect do |extension| extension.grant_type_for? request.grant_type end || request.unsupported_grant_type! end end def extensions Extension.constants.sort.collect do |key| Extension.const_get key end end class Request < Abstract::Request attr_required :grant_type attr_optional :client_secret def initialize(env) auth = Rack::Auth::Basic::Request.new(env) if auth.provided? && auth.basic? @client_id, @client_secret = auth.credentials super else super @client_secret = params['client_secret'] end @grant_type = params['grant_type'].to_s end end class Response < Abstract::Response attr_required :access_token def protocol_params access_token.token_response end def finish attr_missing! write MultiJson.dump(Util.compact_hash(protocol_params)) header['Content-Type'] = 'application/json' header['Cache-Control'] = 'no-store' header['Pragma'] = 'no-cache' super end end end end end end require 'rack/oauth2/server/token/authorization_code' require 'rack/oauth2/server/token/password' require 'rack/oauth2/server/token/client_credentials' require 'rack/oauth2/server/token/refresh_token' require 'rack/oauth2/server/token/jwt_bearer' require 'rack/oauth2/server/token/saml2_bearer' require 'rack/oauth2/server/token/extension' require 'rack/oauth2/server/token/error' rack-oauth2-1.4.0/lib/rack/oauth2/server/token/0000755000004100000410000000000012750322535021206 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/token/client_credentials.rb0000644000004100000410000000076212750322535025373 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class ClientCredentials < Abstract::Handler def call(env) @request = Request.new(env) @response = Response.new(request) super end class Request < Token::Request def initialize(env) super @grant_type = :client_credentials attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/password.rb0000644000004100000410000000115512750322535023377 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class Password < Abstract::Handler def call(env) @request = Request.new(env) @response = Response.new(request) super end class Request < Token::Request attr_required :username, :password def initialize(env) super @grant_type = :password @username = params['username'] @password = params['password'] attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/saml2_bearer.rb0000644000004100000410000000115512750322535024073 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class SAML2Bearer < Abstract::Handler def call(env) @request = Request.new env @response = Response.new request super end class Request < Token::Request attr_required :assertion attr_optional :client_id def initialize(env) super @grant_type = URN::GrantType::SAML2_BEARER @assertion = params['assertion'] attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/extension.rb0000644000004100000410000000042612750322535023551 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token module Extension # Define your extension in this namespace and load it explicitly. # extension/assertion/example.rb would be good example for you. end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/extension/0000755000004100000410000000000012750322535023222 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/server/token/extension/example.rb0000644000004100000410000000160312750322535025202 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token module Extension class Example < Abstract::Handler GRANT_TYPE_URN = 'urn:ietf:params:oauth:grant-type:example' class << self def grant_type_for?(grant_type) grant_type == GRANT_TYPE_URN end end def call(env) @request = Request.new env @response = Response.new request super end class Request < Token::Request attr_required :assertion attr_optional :client_id def initialize(env) super @grant_type = GRANT_TYPE_URN @assertion = params['assertion'] attr_missing! end end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/authorization_code.rb0000644000004100000410000000133212750322535025424 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class AuthorizationCode < Abstract::Handler def call(env) @request = Request.new(env) @response = Response.new(request) super end class Request < Token::Request include Server::Extension::PKCE::TokenRequest attr_required :code attr_optional :redirect_uri def initialize(env) super @grant_type = :authorization_code @code = params['code'] @redirect_uri = params['redirect_uri'] attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/refresh_token.rb0000644000004100000410000000111412750322535024366 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class RefreshToken < Abstract::Handler def call(env) @request = Request.new(env) @response = Response.new(request) super end class Request < Token::Request attr_required :refresh_token def initialize(env) super @grant_type = :refresh_token @refresh_token = params['refresh_token'] attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/token/error.rb0000644000004100000410000000462612750322535022674 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class BadRequest < Abstract::BadRequest end class Unauthorized < Abstract::Unauthorized def finish super do |response| response.header['WWW-Authenticate'] = 'Basic realm="OAuth2 Token Endpoint"' end end end module ErrorMethods DEFAULT_DESCRIPTION = { invalid_request: "The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.", invalid_client: "The client identifier provided is invalid, the client failed to authenticate, the client did not include its credentials, provided multiple client credentials, or used unsupported credentials type.", invalid_grant: "The provided access grant is invalid, expired, or revoked (e.g. invalid assertion, expired authorization token, bad end-user password credentials, or mismatching authorization code and redirection URI).", unauthorized_client: "The authenticated client is not authorized to use the access grant type provided.", unsupported_grant_type: "The access grant included - its type or another attribute - is not supported by the authorization server.", invalid_scope: "The requested scope is invalid, unknown, malformed, or exceeds the previously granted scope." } def self.included(klass) DEFAULT_DESCRIPTION.each do |error, default_description| error_method = if error == :invalid_client :unauthorized! else :bad_request! end klass.class_eval <<-ERROR def #{error}!(description = "#{default_description}", options = {}) #{error_method} :#{error}, description, options end ERROR end end def bad_request!(error, description = nil, options = {}) raise BadRequest.new(error, description, options) end def unauthorized!(error, description = nil, options = {}) raise Unauthorized.new(error, description, options) end end Request.send :include, ErrorMethods end end end end rack-oauth2-1.4.0/lib/rack/oauth2/server/token/jwt_bearer.rb0000644000004100000410000000115112750322535023655 0ustar www-datawww-datamodule Rack module OAuth2 module Server class Token class JWTBearer < Abstract::Handler def call(env) @request = Request.new env @response = Response.new request super end class Request < Token::Request attr_required :assertion attr_optional :client_id def initialize(env) super @grant_type = URN::GrantType::JWT_BEARER @assertion = params['assertion'] attr_missing! end end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server/rails.rb0000644000004100000410000000046512750322535021532 0ustar www-datawww-datamodule Rack module OAuth2 module Server module Rails REQUEST = 'rack_oauth2.request' RESPONSE = 'rack_oauth2.response' ERROR = 'rack_oauth2.error' end end end end require 'rack/oauth2/server/rails/response_ext' require 'rack/oauth2/server/rails/authorize' rack-oauth2-1.4.0/lib/rack/oauth2/server/abstract.rb0000644000004100000410000000026612750322535022222 0ustar www-datawww-datarequire 'rack/oauth2/server/abstract/handler' require 'rack/oauth2/server/abstract/request' require 'rack/oauth2/server/abstract/response' require 'rack/oauth2/server/abstract/error'rack-oauth2-1.4.0/lib/rack/oauth2/access_token.rb0000644000004100000410000000235312750322535021551 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken include AttrRequired, AttrOptional attr_required :access_token, :token_type, :httpclient attr_optional :refresh_token, :expires_in, :scope attr_accessor :raw_attributes delegate :get, :patch, :post, :put, :delete, to: :httpclient alias_method :to_s, :access_token def initialize(attributes = {}) (required_attributes + optional_attributes).each do |key| self.send :"#{key}=", attributes[key] end @raw_attributes = attributes @token_type = self.class.name.demodulize.underscore.to_sym @httpclient = Rack::OAuth2.http_client("#{self.class} (#{VERSION})") do |config| config.request_filter << Authenticator.new(self) end attr_missing! end def token_response(options = {}) { access_token: access_token, refresh_token: refresh_token, token_type: token_type, expires_in: expires_in, scope: Array(scope).join(' ') } end end end end require 'rack/oauth2/access_token/authenticator' require 'rack/oauth2/access_token/bearer' require 'rack/oauth2/access_token/mac' require 'rack/oauth2/access_token/legacy' rack-oauth2-1.4.0/lib/rack/oauth2/client.rb0000644000004100000410000001111312750322535020360 0ustar www-datawww-datamodule Rack module OAuth2 class Client include AttrRequired, AttrOptional attr_required :identifier attr_optional :secret, :redirect_uri, :scheme, :host, :port, :authorization_endpoint, :token_endpoint def initialize(attributes = {}) (required_attributes + optional_attributes).each do |key| self.send :"#{key}=", attributes[key] end @grant = Grant::ClientCredentials.new @authorization_endpoint ||= '/oauth2/authorize' @token_endpoint ||= '/oauth2/token' attr_missing! end def authorization_uri(params = {}) params[:response_type] ||= :code params[:response_type] = Array(params[:response_type]).join(' ') params[:scope] = Array(params[:scope]).join(' ') Util.redirect_uri absolute_uri_for(authorization_endpoint), :query, params.merge( client_id: self.identifier, redirect_uri: self.redirect_uri ) end def authorization_code=(code) @grant = Grant::AuthorizationCode.new( code: code, redirect_uri: self.redirect_uri ) end def resource_owner_credentials=(credentials) @grant = Grant::Password.new( username: credentials.first, password: credentials.last ) end def refresh_token=(token) @grant = Grant::RefreshToken.new( refresh_token: token ) end def jwt_bearer=(assertion) @grant = Grant::JWTBearer.new( assertion: assertion ) end def saml2_bearer=(assertion) @grant = Grant::SAML2Bearer.new( assertion: assertion ) end def subject_token=(subject_token, subject_token_type = URN::TokenType::JWT) @grant = Grant::TokenExchange.new( subject_token: subject_token, subject_token_type: subject_token_type ) end def access_token!(*args) headers, params = {}, @grant.as_json # NOTE: # Using Array#estract_options! for backward compatibility. # Until v1.0.5, the first argument was 'client_auth_method' in scalar. options = args.extract_options! client_auth_method = args.first || options.delete(:client_auth_method) || :basic params[:scope] = Array(options.delete(:scope)).join(' ') if options[:scope].present? params.merge! options if secret && client_auth_method == :basic cred = ["#{identifier}:#{secret}"].pack('m').tr("\n", '') headers.merge!( 'Authorization' => "Basic #{cred}" ) else params.merge!( client_id: identifier, client_secret: secret ) end handle_response do Rack::OAuth2.http_client.post( absolute_uri_for(token_endpoint), Util.compact_hash(params), headers ) end end private def absolute_uri_for(endpoint) _endpoint_ = Util.parse_uri endpoint _endpoint_.scheme ||= self.scheme || 'https' _endpoint_.host ||= self.host _endpoint_.port ||= self.port raise 'No Host Info' unless _endpoint_.host _endpoint_.to_s end def handle_response response = yield case response.status when 200..201 handle_success_response response else handle_error_response response end end def handle_success_response(response) token_hash = parse_json response.body case token_hash[:token_type].try(:downcase) when 'bearer' AccessToken::Bearer.new(token_hash) when 'mac' AccessToken::MAC.new(token_hash) when nil AccessToken::Legacy.new(token_hash) else raise 'Unknown Token Type' end rescue MultiJson::DecodeError # NOTE: Facebook support (They don't use JSON as token response) AccessToken::Legacy.new Rack::Utils.parse_nested_query(response.body).with_indifferent_access end def handle_error_response(response) error = parse_json response.body raise Error.new(response.status, error) rescue MultiJson::DecodeError raise Error.new(response.status, error: 'Unknown', error_description: response.body) end def parse_json(raw_json) # MultiJson.parse('') returns nil when using MultiJson::Adapters::JsonGem MultiJson.load(raw_json).try(:with_indifferent_access) || {} end end end end require 'rack/oauth2/client/error' require 'rack/oauth2/client/grant' rack-oauth2-1.4.0/lib/rack/oauth2/access_token/0000755000004100000410000000000012750322535021221 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/access_token/mac/0000755000004100000410000000000012750322535021761 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/access_token/mac/signature.rb0000644000004100000410000000136312750322535024312 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class MAC class Signature < Verifier attr_required :secret, :ts, :nonce, :method, :request_uri, :host, :port attr_optional :ext, :query def calculate Rack::OAuth2::Util.base64_encode OpenSSL::HMAC.digest( hash_generator, secret, normalized_request_string ) end def normalized_request_string [ ts.to_i, nonce, method.to_s.upcase, request_uri, host, port, ext || '', nil ].join("\n") end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/access_token/mac/sha256_hex_verifier.rb0000644000004100000410000000054612750322535026062 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class MAC class Sha256HexVerifier < Verifier attr_optional :raw_body def calculate return nil unless raw_body.present? OpenSSL::Digest::SHA256.new.digest(raw_body).unpack('H*').first end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/access_token/mac/verifier.rb0000644000004100000410000000223112750322535024117 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class MAC class Verifier include AttrRequired, AttrOptional attr_required :algorithm class VerificationFailed < StandardError; end def initialize(attributes = {}) (required_attributes + optional_attributes).each do |key| self.send :"#{key}=", attributes[key] end attr_missing! rescue AttrRequired::AttrMissing => e raise VerificationFailed.new("#{self.class.name.demodulize} Invalid: #{e.message}") end def verify!(expected) if expected == self.calculate :verified else raise VerificationFailed.new("#{self.class.name.demodulize} Invalid") end end private def hash_generator case algorithm.to_s when 'hmac-sha-1' OpenSSL::Digest::SHA1.new when 'hmac-sha-256' OpenSSL::Digest::SHA256.new else raise 'Unsupported Algorithm' end end end end end end end rack-oauth2-1.4.0/lib/rack/oauth2/access_token/bearer.rb0000644000004100000410000000034112750322535023004 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class Bearer < AccessToken def authenticate(request) request.header["Authorization"] = "Bearer #{access_token}" end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/access_token/authenticator.rb0000644000004100000410000000110712750322535024417 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class Authenticator def initialize(token) @token = token end # Callback called in HTTPClient (before sending a request) # request:: HTTP::Message def filter_request(request) @token.authenticate(request) end # Callback called in HTTPClient (after received a response) # response:: HTTP::Message # request:: HTTP::Message def filter_response(response, request) # nothing to do end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/access_token/legacy.rb0000644000004100000410000000063212750322535023013 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class Legacy < AccessToken def initialize(attributes = {}) super self.expires_in = ( self.expires_in || attributes[:expires] ).try(:to_i) end def authenticate(request) request.header["Authorization"] = "OAuth #{access_token}" end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/access_token/mac.rb0000644000004100000410000000611312750322535022307 0ustar www-datawww-datamodule Rack module OAuth2 class AccessToken class MAC < AccessToken attr_required :mac_key, :mac_algorithm attr_optional :ts, :ext_verifier, :ts_expires_in attr_reader :nonce, :signature, :ext def initialize(attributes = {}) super(attributes) @issued_at = Time.now.utc @ts_expires_in ||= 5.minutes end def token_response super.merge( mac_key: mac_key, mac_algorithm: mac_algorithm ) end def verify!(request) if self.ext_verifier.present? body = request.body.read request.body.rewind # for future use self.ext_verifier.new( raw_body: body, algorithm: self.mac_algorithm ).verify!(request.ext) end now = Time.now.utc.to_i now = @ts.to_i if @ts.present? raise Rack::OAuth2::AccessToken::MAC::Verifier::VerificationFailed.new("Request ts expired") if now - request.ts.to_i > @ts_expires_in.to_i Signature.new( secret: self.mac_key, algorithm: self.mac_algorithm, nonce: request.nonce, method: request.request_method, request_uri: request.fullpath, host: request.host, port: request.port, ts: request.ts, ext: request.ext ).verify!(request.signature) rescue Verifier::VerificationFailed => e request.invalid_token! e.message end def authenticate(request) @nonce = generate_nonce @ts_generated = @ts || Time.now.utc if self.ext_verifier.present? @ext = self.ext_verifier.new( raw_body: request.body, algorithm: self.mac_algorithm ).calculate end @signature = Signature.new( secret: self.mac_key, algorithm: self.mac_algorithm, nonce: self.nonce, method: request.header.request_method, request_uri: request.header.create_query_uri, host: request.header.request_uri.host, port: request.header.request_uri.port, ts: @ts_generated, ext: @ext ).calculate request.header['Authorization'] = authorization_header end private def authorization_header header = "MAC id=\"#{access_token}\"" header << ", nonce=\"#{nonce}\"" header << ", ts=\"#{@ts_generated.to_i}\"" header << ", mac=\"#{signature}\"" header << ", ext=\"#{ext}\"" if @ext.present? header end def generate_nonce [ (Time.now.utc - @issued_at).to_i, SecureRandom.hex ].join(':') end end end end end require 'rack/oauth2/access_token/mac/verifier' require 'rack/oauth2/access_token/mac/sha256_hex_verifier' require 'rack/oauth2/access_token/mac/signature' rack-oauth2-1.4.0/lib/rack/oauth2/client/0000755000004100000410000000000012750322535020036 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/client/grant/0000755000004100000410000000000012750322535021151 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/client/grant/token_exchange.rb0000644000004100000410000000043112750322535024456 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class TokenExchange < Grant attr_required :subject_token, :subject_token_type def grant_type URN::GrantType::TOKEN_EXCHANGE end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/client_credentials.rb0000644000004100000410000000021612750322535025330 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class ClientCredentials < Grant end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/password.rb0000644000004100000410000000026212750322535023340 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class Password < Grant attr_required :username, :password end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/saml2_bearer.rb0000644000004100000410000000037412750322535024040 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class SAML2Bearer < Grant attr_required :assertion def grant_type URN::GrantType::SAML2_BEARER end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/authorization_code.rb0000644000004100000410000000032212750322535025365 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class AuthorizationCode < Grant attr_required :code attr_optional :redirect_uri end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/refresh_token.rb0000644000004100000410000000026012750322535024332 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class RefreshToken < Grant attr_required :refresh_token end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant/jwt_bearer.rb0000644000004100000410000000037012750322535023622 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant class JWTBearer < Grant attr_required :assertion def grant_type URN::GrantType::JWT_BEARER end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/client/grant.rb0000644000004100000410000000176312750322535021505 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Grant include AttrRequired, AttrOptional def initialize(attributes = {}) (required_attributes + optional_attributes).each do |key| self.send "#{key}=", attributes[key] end attr_missing! end def grant_type self.class.name.demodulize.underscore.to_sym end def as_json(options = {}) (required_attributes + optional_attributes).inject({ grant_type: grant_type }) do |hash, key| hash.merge! key => self.send(key) end end end end end end require 'rack/oauth2/client/grant/authorization_code' require 'rack/oauth2/client/grant/password' require 'rack/oauth2/client/grant/client_credentials' require 'rack/oauth2/client/grant/refresh_token' require 'rack/oauth2/client/grant/jwt_bearer' require 'rack/oauth2/client/grant/saml2_bearer' require 'rack/oauth2/client/grant/token_exchange'rack-oauth2-1.4.0/lib/rack/oauth2/client/error.rb0000644000004100000410000000045712750322535021522 0ustar www-datawww-datamodule Rack module OAuth2 class Client class Error < StandardError attr_accessor :status, :response def initialize(status, response) @status = status @response = response super response[:error_description] end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/debugger/0000755000004100000410000000000012750322535020344 5ustar www-datawww-datarack-oauth2-1.4.0/lib/rack/oauth2/debugger/request_filter.rb0000644000004100000410000000147112750322535023731 0ustar www-datawww-datamodule Rack module OAuth2 module Debugger class RequestFilter # Callback called in HTTPClient (before sending a request) # request:: HTTP::Message def filter_request(request) started = "======= [Rack::OAuth2] HTTP REQUEST STARTED =======" log started, request.dump end # Callback called in HTTPClient (after received a response) # request:: HTTP::Message # response:: HTTP::Message def filter_response(request, response) finished = "======= [Rack::OAuth2] HTTP REQUEST FINISHED =======" log '-' * 50, response.dump, finished end private def log(*outputs) outputs.each do |output| OAuth2.logger.info output end end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/urn.rb0000644000004100000410000000164312750322535017715 0ustar www-datawww-datamodule Rack module OAuth2 module URN module TokenType JWT = 'urn:ietf:params:oauth:token-type:jwt' # RFC7519 ACCESS_TOKEN = 'urn:ietf:params:oauth:token-type:access-token' # draft-ietf-oauth-token-exchange REFRESH_TOKEN = 'urn:ietf:params:oauth:token-type:refresh-token' # draft-ietf-oauth-token-exchange end module GrantType JWT_BEARER = 'urn:ietf:params:oauth:grant-type:jwt-bearer' # RFC7523 SAML2_BEARER = 'urn:ietf:params:oauth:grant-type:saml2-bearer' # RFC7522 TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange' # draft-ietf-oauth-token-exchange end module ClientAssertionType JWT_BEARER = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' # RFC7523 SAML2_BEARER = 'urn:ietf:params:oauth:client-assertion-type:saml2-bearer' # RFC7522 end end end endrack-oauth2-1.4.0/lib/rack/oauth2/util.rb0000644000004100000410000000303612750322535020064 0ustar www-datawww-datarequire 'base64' module Rack module OAuth2 module Util class << self def rfc3986_encode(text) URI.encode(text, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) end def base64_encode(text) Base64.encode64(text).delete("\n") end def urlsafe_base64_encode(text) Base64.urlsafe_encode64(text).delete('=') end def compact_hash(hash) hash.reject do |key, value| value.blank? end end def parse_uri(uri) case uri when URI::Generic uri when String URI.parse(uri) else raise "Invalid format of URI is given." end end def redirect_uri(base_uri, location, params) redirect_uri = parse_uri base_uri case location when :query redirect_uri.query = [redirect_uri.query, Util.compact_hash(params).to_query].compact.join('&') when :fragment redirect_uri.fragment = Util.compact_hash(params).to_query end redirect_uri.to_s end def uri_match?(base, given) base = parse_uri(base) given = parse_uri(given) base.path = '/' if base.path.blank? given.path = '/' if given.path.blank? [:scheme, :host, :port].all? do |key| base.send(key) == given.send(key) end && !!(/^#{base.path}/ =~ given.path) rescue false end end end end endrack-oauth2-1.4.0/lib/rack/oauth2/server.rb0000644000004100000410000000034012750322535020410 0ustar www-datawww-datarequire 'rack/oauth2/server/abstract' require 'rack/oauth2/server/extension' require 'rack/oauth2/server/authorize' require 'rack/oauth2/server/token' require 'rack/oauth2/server/resource' require 'rack/oauth2/server/rails' rack-oauth2-1.4.0/lib/rack/oauth2.rb0000644000004100000410000000304712750322535017111 0ustar www-datawww-datarequire 'rack' require 'multi_json' require 'httpclient' require 'logger' require 'active_support' require 'active_support/core_ext' require 'attr_required' require 'attr_optional' module Rack module OAuth2 VERSION = ::File.read( ::File.join(::File.dirname(__FILE__), '../../VERSION') ).strip def self.logger @@logger end def self.logger=(logger) @@logger = logger end self.logger = ::Logger.new(STDOUT) self.logger.progname = 'Rack::OAuth2' def self.debugging? @@debugging end def self.debugging=(boolean) @@debugging = boolean end def self.debug! self.debugging = true end def self.debug(&block) original = self.debugging? self.debugging = true yield ensure self.debugging = original end self.debugging = false def self.http_client(agent_name = "Rack::OAuth2 (#{VERSION})", &local_http_config) _http_client_ = HTTPClient.new( agent_name: agent_name ) http_config.try(:call, _http_client_) local_http_config.try(:call, _http_client_) unless local_http_config.nil? _http_client_.request_filter << Debugger::RequestFilter.new if debugging? _http_client_ end def self.http_config(&block) @@http_config ||= block end def self.reset_http_config! @@http_config = nil end end end require 'rack/oauth2/urn' require 'rack/oauth2/util' require 'rack/oauth2/server' require 'rack/oauth2/client' require 'rack/oauth2/access_token' require 'rack/oauth2/debugger' rack-oauth2-1.4.0/.gitignore0000644000004100000410000000024012750322535015654 0ustar www-datawww-data## MAC OS .DS_Store ## TEXTMATE *.tmproj tmtags ## EMACS *~ \#* .\#* ## VIM *.swp ## PROJECT::GENERAL coverage* rdoc pkg Gemfile.lock ## PROJECT::SPECIFIC rack-oauth2-1.4.0/LICENSE0000644000004100000410000000203612750322535014676 0ustar www-datawww-dataCopyright (c) 2010 nov matake Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rack-oauth2-1.4.0/VERSION0000644000004100000410000000000512750322535014733 0ustar www-datawww-data1.4.0rack-oauth2-1.4.0/rack-oauth2.gemspec0000644000004100000410000000245012750322535017356 0ustar www-datawww-dataGem::Specification.new do |s| s.name = "rack-oauth2" s.version = File.read("VERSION") s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version= s.authors = ["nov matake"] s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer and MAC token type are supported.} s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer and MAC token type are supported} s.email = "nov@matake.jp" s.extra_rdoc_files = ["LICENSE", "README.rdoc"] s.rdoc_options = ["--charset=UTF-8"] s.homepage = "http://github.com/nov/rack-oauth2" s.license = 'MIT' s.require_paths = ["lib"] s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.add_runtime_dependency "rack", ">= 1.1" s.add_runtime_dependency "multi_json", ">= 1.3.6" s.add_runtime_dependency "httpclient", ">= 2.4" s.add_runtime_dependency "activesupport", ">= 2.3" s.add_runtime_dependency "attr_required", ">= 0.0.5" s.add_development_dependency "rake", ">= 0.8" s.add_development_dependency "simplecov" s.add_development_dependency "rspec" s.add_development_dependency "rspec-its" s.add_development_dependency "webmock", "< 1.24" end rack-oauth2-1.4.0/.document0000644000004100000410000000007412750322535015510 0ustar www-datawww-dataREADME.rdoc lib/**/*.rb bin/* features/**/*.feature LICENSE