# Copyright (C) 2010 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' require 'signet/errors' require 'signet/oauth_2' describe Signet::OAuth2 do # This behavior will almost certainly change in subsequent updates. describe 'when parsing an Authorization header' do it 'should correctly handle HTTP Basic auth-scheme' do parameters = Signet::OAuth2.parse_authorization_header( 'Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['client_id']).to eq 's6BhdRkqt3' expect(parameters['client_secret']).to eq 'gX1fBat3bV' end it 'should correctly handle OAuth auth-scheme' do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['access_token']).to eq 'vF9dft4qmT' end it 'should correctly handle OAuth auth-scheme with realm' do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT, realm="http://sp.example.com/"' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['access_token']).to eq 'vF9dft4qmT' expect(parameters['realm']).to eq 'http://sp.example.com/' end it 'should correctly handle OAuth auth-scheme with multiple auth-params' do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT, first="one", second="two"' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['access_token']).to eq 'vF9dft4qmT' expect(parameters['first']).to eq 'one' expect(parameters['second']).to eq 'two' end it 'should liberally handle auth-params with single-quoted strings' do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT, first=\'one\', second=\'two\'' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['access_token']).to eq 'vF9dft4qmT' expect(parameters['first']).to eq 'one' expect(parameters['second']).to eq 'two' end it 'should liberally handle auth-params with unquoted strings' do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT, first=one, second=two' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['access_token']).to eq 'vF9dft4qmT' expect(parameters['first']).to eq 'one' expect(parameters['second']).to eq 'two' end it 'should not allow unquoted strings that do not match tchar' do expect(lambda do parameters = Signet::OAuth2.parse_authorization_header( 'OAuth vF9dft4qmT, first=one:1' ) end).to raise_error(Signet::ParseError) end it 'should not parse non-OAuth auth-schemes' do expect(lambda do Signet::OAuth2.parse_authorization_header( 'AuthSub token="GD32CMCL25aZ-v____8B"' ) end).to raise_error(Signet::ParseError) end end # This behavior will almost certainly change in subsequent updates. describe 'when parsing a WWW-Authenticate header' do it 'should correctly handle OAuth challenge with auth-params' do parameters = Signet::OAuth2.parse_www_authenticate_header( 'OAuth realm="http://sp.example.com/", error="expired_token", ' + 'error_description="The access token has expired."' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['realm']).to eq 'http://sp.example.com/' expect(parameters['error']).to eq 'expired_token' expect(parameters['error_description']).to eq 'The access token has expired.' end it 'should liberally handle auth-params with single-quoted strings' do parameters = Signet::OAuth2.parse_www_authenticate_header( 'OAuth realm=\'http://sp.example.com/\', error=\'expired_token\', ' + 'error_description=\'The access token has expired.\'' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['realm']).to eq 'http://sp.example.com/' expect(parameters['error']).to eq 'expired_token' expect(parameters['error_description']).to eq 'The access token has expired.' end it 'should liberally handle auth-params with token strings' do parameters = Signet::OAuth2.parse_www_authenticate_header( 'OAuth realm="http://sp.example.com/", error=expired_token, ' + 'error_description="The access token has expired."' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['realm']).to eq 'http://sp.example.com/' expect(parameters['error']).to eq 'expired_token' expect(parameters['error_description']).to eq 'The access token has expired.' end it 'should liberally handle out-of-order auth-params' do parameters = Signet::OAuth2.parse_www_authenticate_header( 'OAuth error_description=\'The access token has expired.\', ' + 'error=\'expired_token\', realm=\'http://sp.example.com/\'' ).inject({}) { |h,(k,v)| h[k]=v; h } expect(parameters['realm']).to eq 'http://sp.example.com/' expect(parameters['error']).to eq 'expired_token' expect(parameters['error_description']).to eq 'The access token has expired.' end it 'should not allow unquoted strings that do not match tchar' do expect(lambda do Signet::OAuth2.parse_www_authenticate_header( 'OAuth realm=http://sp.example.com/, error=expired_token, ' + 'error_description="The access token has expired."' ) end).to raise_error(Signet::ParseError) end it 'should not parse non-OAuth challenges' do expect(lambda do Signet::OAuth2.parse_www_authenticate_header( 'AuthSub realm="https://www.google.com/accounts/AuthSubRequest"' ) end).to raise_error(Signet::ParseError) end end describe 'when generating a Basic Authorization header' do it 'should correctly handle client ID and password pairs' do # Example from OAuth 2 spec expect(Signet::OAuth2.generate_basic_authorization_header( 's6BhdRkqt3', 'gX1fBat3bV' )).to eq 'Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW' end it 'should correctly encode using the alogrithm given in RFC 2617' do # Example from RFC 2617 expect(Signet::OAuth2.generate_basic_authorization_header( 'Aladdin', 'open sesame' )).to eq 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' end end describe 'when parsing a token response body' do it 'should correctly handle just an access token' do expect(Signet::OAuth2.parse_credentials( '{"access_token": "12345"}', 'application/json; charset=utf-8' )).to eq ({"access_token" => "12345"}) end it 'should handle form encoded responses' do expect(Signet::OAuth2.parse_credentials( 'access_token=12345&expires=1000', 'application/x-www-form-urlencoded; charset=utf-8' )).to eq({"access_token" => "12345", "expires" => "1000" }) end it 'should raise an error for an invalid body' do expect(lambda do Signet::OAuth2.parse_credentials( 'This is not JSON.', 'application/json' ) end).to raise_error(MultiJson::DecodeError) end it 'should raise an error for a bogus body' do expect(lambda do Signet::OAuth2.parse_credentials(:bogus, 'application/json') end).to raise_error(TypeError) end end end