pax_global_header 0000666 0000000 0000000 00000000064 14542752767 0014535 g ustar 00root root 0000000 0000000 52 comment=70da234801c53a116c2d8e126bb09f237824af5a
rack-oauth2-2.2.1/ 0000775 0000000 0000000 00000000000 14542752767 0013657 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/.document 0000664 0000000 0000000 00000000074 14542752767 0015477 0 ustar 00root root 0000000 0000000 README.rdoc
lib/**/*.rb
bin/*
features/**/*.feature
LICENSE
rack-oauth2-2.2.1/.github/ 0000775 0000000 0000000 00000000000 14542752767 0015217 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/.github/FUNDING.yml 0000664 0000000 0000000 00000000073 14542752767 0017034 0 ustar 00root root 0000000 0000000 # These are supported funding model platforms
github: nov
rack-oauth2-2.2.1/.github/workflows/ 0000775 0000000 0000000 00000000000 14542752767 0017254 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/.github/workflows/spec.yml 0000664 0000000 0000000 00000001103 14542752767 0020724 0 ustar 00root root 0000000 0000000 name: Spec
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
jobs:
spec:
strategy:
matrix:
os: ['ubuntu-20.04', 'ubuntu-22.04']
ruby-version: ['3.1', '3.2', '3.3']
include:
- os: 'ubuntu-20.04'
ruby-version: '3.0'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true
- name: Run Specs
run: bundle exec rake spec
rack-oauth2-2.2.1/.gitignore 0000664 0000000 0000000 00000000240 14542752767 0015643 0 ustar 00root root 0000000 0000000 ## MAC OS
.DS_Store
## TEXTMATE
*.tmproj
tmtags
## EMACS
*~
\#*
.\#*
## VIM
*.swp
## PROJECT::GENERAL
coverage*
rdoc
pkg
Gemfile.lock
## PROJECT::SPECIFIC
rack-oauth2-2.2.1/.rspec 0000664 0000000 0000000 00000000037 14542752767 0014774 0 ustar 00root root 0000000 0000000 --color
--format=documentation
rack-oauth2-2.2.1/CHANGELOG.md 0000664 0000000 0000000 00000001561 14542752767 0015473 0 ustar 00root root 0000000 0000000 ## [Unreleased]
## [2.2.0] - 2022-10-11
### Changed
- automatic json response decoding, and remove legacy token support by @nov in https://github.com/nov/rack-oauth2/pull/95
## [2.1.0] - 2022-10-10
### Added
- accept local_http_config on Rack::OAuth2::Client#access_token! & revoke! to support custom headers etc. by @nov in https://github.com/nov/rack-oauth2/pull/93
## [2.0.1] - 2022-10-09
### Fixed
- changes for mTLS on faraday by @nov in https://github.com/nov/rack-oauth2/pull/92
## [2.0.0] - 2022-10-09
### Added
- start recording CHANGELOG
### Changed
- Switch from httpclient to faraday v2 https://github.com/nov/rack-oauth2/pull/91
- make url-encoded the default https://github.com/nov/rack-oauth2/commit/98faf139be4f5bf9ec6134d31f65a298259d8a8b
- let faraday encode params https://github.com/nov/rack-oauth2/commit/f399b3afb8facb3635b8842baee8584bc4d3ce73 rack-oauth2-2.2.1/Gemfile 0000664 0000000 0000000 00000000140 14542752767 0015145 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
platforms :jruby do
gem 'jruby-openssl', '>= 0.7'
end
gemspec
rack-oauth2-2.2.1/LICENSE 0000664 0000000 0000000 00000002036 14542752767 0014665 0 ustar 00root root 0000000 0000000 Copyright (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-2.2.1/README.rdoc 0000664 0000000 0000000 00000002765 14542752767 0015477 0 ustar 00root root 0000000 0000000 = rack-oauth2
OAuth 2.0 Server & Client Library.
Both Bearer token type are supported.
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
== 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
Source on GitHub
https://github.com/nov/rack-oauth2-sample
== Sample Client
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
Resource Request (request both for resource owner resource and for client resource)
https://gist.github.com/883575
== 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-2.2.1/Rakefile 0000664 0000000 0000000 00000000620 14542752767 0015322 0 ustar 00root root 0000000 0000000 require '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-2.2.1/VERSION 0000664 0000000 0000000 00000000005 14542752767 0014722 0 ustar 00root root 0000000 0000000 2.2.1 rack-oauth2-2.2.1/lib/ 0000775 0000000 0000000 00000000000 14542752767 0014425 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/ 0000775 0000000 0000000 00000000000 14542752767 0015345 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2.rb 0000664 0000000 0000000 00000003141 14542752767 0017073 0 ustar 00root root 0000000 0000000 require 'rack'
require 'faraday'
require 'faraday/follow_redirects'
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)
Faraday.new(headers: {user_agent: agent_name}) do |faraday|
faraday.request :url_encoded
faraday.request :json
faraday.response :json
faraday.adapter Faraday.default_adapter
local_http_config&.call(faraday)
http_config&.call(faraday)
faraday.response :logger, Rack::OAuth2.logger, bodies: true if debugging?
end
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'
rack-oauth2-2.2.1/lib/rack/oauth2/ 0000775 0000000 0000000 00000000000 14542752767 0016547 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/access_token.rb 0000664 0000000 0000000 00000002330 14542752767 0021533 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class AccessToken
include AttrRequired, AttrOptional
attr_required :access_token, :token_type
attr_optional :refresh_token, :expires_in, :scope
attr_accessor :raw_attributes
delegate :get, :patch, :post, :put, :delete, to: :http_client
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
attr_missing!
end
def http_client
@http_client ||= Rack::OAuth2.http_client("#{self.class} (#{VERSION})") do |faraday|
Authenticator.new(self).authenticate(faraday)
end
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/mtls'
rack-oauth2-2.2.1/lib/rack/oauth2/access_token/ 0000775 0000000 0000000 00000000000 14542752767 0021210 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/access_token/authenticator.rb 0000664 0000000 0000000 00000000400 14542752767 0024401 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class AccessToken
class Authenticator
def initialize(token)
@token = token
end
def authenticate(request)
@token.authenticate(request)
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/access_token/bearer.rb 0000664 0000000 0000000 00000000662 14542752767 0023001 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class AccessToken
class Bearer < AccessToken
def authenticate(request)
request.headers["Authorization"] = "Bearer #{access_token}"
end
def to_mtls(attributes = {})
(required_attributes + optional_attributes).each do |key|
attributes[key] = self.send(key)
end
MTLS.new attributes
end
end
end
end
end
rack-oauth2-2.2.1/lib/rack/oauth2/access_token/mtls.rb 0000664 0000000 0000000 00000000551 14542752767 0022515 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class AccessToken
class MTLS < Bearer
attr_required :private_key, :certificate
def initialize(attributes = {})
super
self.token_type = :bearer
http_client.ssl.client_key = private_key
http_client.ssl.client_cert = certificate
end
end
end
end
end
rack-oauth2-2.2.1/lib/rack/oauth2/client.rb 0000664 0000000 0000000 00000016117 14542752767 0020360 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
include AttrRequired, AttrOptional
attr_required :identifier
attr_optional :secret, :private_key, :certificate, :redirect_uri, :scheme, :host, :port, :authorization_endpoint, :token_endpoint, :revocation_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[:redirect_uri] ||= self.redirect_uri
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
)
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 force_token_type!(token_type)
@forced_token_type = token_type.to_s
end
def access_token!(*args)
headers, params, http_client, options = authenticated_context_from(*args)
params[:scope] = Array(options.delete(:scope)).join(' ') if options[:scope].present?
params.merge! @grant.as_json
params.merge! options
handle_response do
http_client.post(
absolute_uri_for(token_endpoint),
Util.compact_hash(params),
headers
) do |req|
yield req if block_given?
end
end
end
def revoke!(*args)
headers, params, http_client, options = authenticated_context_from(*args)
params.merge! case
when access_token = options.delete(:access_token)
{
token: access_token,
token_type_hint: :access_token
}
when refresh_token = options.delete(:refresh_token)
{
token: refresh_token,
token_type_hint: :refresh_token
}
when @grant.is_a?(Grant::RefreshToken)
{
token: @grant.refresh_token,
token_type_hint: :refresh_token
}
when options[:token].blank?
raise ArgumentError, 'One of "token", "access_token" and "refresh_token" is required'
end
params.merge! options
handle_revocation_response do
http_client.post(
absolute_uri_for(revocation_endpoint),
Util.compact_hash(params),
headers
) do |req|
yield req if block_given?
end
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 authenticated_context_from(*args)
headers, params = {}, {}
http_client = Rack::OAuth2.http_client
# NOTE:
# Using Array#extract_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)&.to_sym || :basic
case client_auth_method
when :basic
cred = Base64.strict_encode64 [
Util.www_form_url_encode(identifier),
Util.www_form_url_encode(secret)
].join(':')
headers.merge!(
'Authorization' => "Basic #{cred}"
)
when :basic_without_www_form_urlencode
cred = ["#{identifier}:#{secret}"].pack('m').tr("\n", '')
headers.merge!(
'Authorization' => "Basic #{cred}"
)
when :jwt_bearer
params.merge!(
client_assertion_type: URN::ClientAssertionType::JWT_BEARER
)
# NOTE: optionally auto-generate client_assertion.
params[:client_assertion] = if options[:client_assertion].present?
options.delete(:client_assertion)
else
require 'json/jwt'
JSON::JWT.new(
iss: identifier,
sub: identifier,
aud: absolute_uri_for(token_endpoint),
jti: SecureRandom.hex(16),
iat: Time.now,
exp: 3.minutes.from_now
).sign(private_key || secret).to_s
end
when :saml2_bearer
params.merge!(
client_assertion_type: URN::ClientAssertionType::SAML2_BEARER
)
when :mtls
params.merge!(
client_id: identifier
)
http_client.ssl.client_key = private_key
http_client.ssl.client_cert = certificate
else
params.merge!(
client_id: identifier,
client_secret: secret
)
end
[headers, params, http_client, options]
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_revocation_response
response = yield
case response.status
when 200..201
:success
else
handle_error_response response
end
end
def handle_success_response(response)
token_hash = response.body.with_indifferent_access
case (@forced_token_type || token_hash[:token_type])&.downcase
when 'bearer'
AccessToken::Bearer.new(token_hash)
else
raise 'Unknown Token Type'
end
end
def handle_error_response(response)
error = response.body.with_indifferent_access
raise Error.new(response.status, error)
rescue Faraday::ParsingError, NoMethodError
raise Error.new(response.status, error: 'Unknown', error_description: response.body)
end
end
end
end
require 'rack/oauth2/client/error'
require 'rack/oauth2/client/grant'
rack-oauth2-2.2.1/lib/rack/oauth2/client/ 0000775 0000000 0000000 00000000000 14542752767 0020025 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/client/error.rb 0000664 0000000 0000000 00000000565 14542752767 0021511 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
class Error < StandardError
attr_accessor :status, :response
def initialize(status, response)
@status = status
@response = response
message = [response[:error], response[:error_description]].compact.join(' :: ')
super message
end
end
end
end
end
rack-oauth2-2.2.1/lib/rack/oauth2/client/grant.rb 0000664 0000000 0000000 00000001763 14542752767 0021474 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/client/grant/ 0000775 0000000 0000000 00000000000 14542752767 0021140 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/authorization_code.rb 0000664 0000000 0000000 00000000322 14542752767 0025354 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
class Grant
class AuthorizationCode < Grant
attr_required :code
attr_optional :redirect_uri
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/client_credentials.rb 0000664 0000000 0000000 00000000216 14542752767 0025317 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
class Grant
class ClientCredentials < Grant
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/jwt_bearer.rb 0000664 0000000 0000000 00000000370 14542752767 0023611 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/password.rb 0000664 0000000 0000000 00000000262 14542752767 0023327 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
class Grant
class Password < Grant
attr_required :username, :password
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/refresh_token.rb 0000664 0000000 0000000 00000000260 14542752767 0024321 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
class Client
class Grant
class RefreshToken < Grant
attr_required :refresh_token
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/saml2_bearer.rb 0000664 0000000 0000000 00000000374 14542752767 0024027 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/client/grant/token_exchange.rb 0000664 0000000 0000000 00000000431 14542752767 0024445 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server.rb 0000664 0000000 0000000 00000000340 14542752767 0020377 0 ustar 00root root 0000000 0000000 require '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-2.2.1/lib/rack/oauth2/server/ 0000775 0000000 0000000 00000000000 14542752767 0020055 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/abstract.rb 0000664 0000000 0000000 00000000266 14542752767 0022211 0 ustar 00root root 0000000 0000000 require '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-2.2.1/lib/rack/oauth2/server/abstract/ 0000775 0000000 0000000 00000000000 14542752767 0021660 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/abstract/error.rb 0000664 0000000 0000000 00000004200 14542752767 0023332 0 ustar 00root root 0000000 0000000 module 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.headers['Content-Type'] = 'application/json'
response.write Util.compact_hash(protocol_params).to_json
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 = {})
@skip_www_authenticate = options[:skip_www_authenticate]
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 = :server_error, description = nil, options = {})
super 500, error, description, options
end
end
class TemporarilyUnavailable < Error
def initialize(error = :temporarily_unavailable, description = nil, options = {})
super 503, error, description, options
end
end
end
end
end
end
rack-oauth2-2.2.1/lib/rack/oauth2/server/abstract/handler.rb 0000664 0000000 0000000 00000001456 14542752767 0023630 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
module Server
module Abstract
class Handler
attr_accessor :authenticator, :request, :response
def initialize(&authenticator)
@authenticator = authenticator
end
def call(env)
# NOTE:
# Rack middleware is initialized only on the first request of the process.
# So any instance variables are acts like class variables, and modifying them in call() isn't thread-safe.
# ref.) http://stackoverflow.com/questions/23028226/rack-middleware-and-thread-safety
dup._call(env)
end
def _call(env)
@authenticator.call(@request, @response) if @authenticator
@response
end
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/server/abstract/request.rb 0000664 0000000 0000000 00000001427 14542752767 0023701 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/abstract/response.rb 0000664 0000000 0000000 00000000420 14542752767 0024037 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
module Server
module Abstract
class Response < Rack::Response
include AttrRequired, AttrOptional
def initialize(request)
super([], 200, {})
end
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/server/authorize.rb 0000664 0000000 0000000 00000007120 14542752767 0022414 0 ustar 00root root 0000000 0000000 module 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
include Server::Extension::ResponseMode::AuthorizationRequest
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.
invalid_request! '"client_id" missing' if client_id.blank?
@redirect_uri = Util.parse_uri(params['redirect_uri']) if params['redirect_uri']
@response_mode = params['response_mode']
@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
invalid_request! '"redirect_uri" mismatch'
end
elsif pre_registered.present? && Array(pre_registered).size == 1 && !allow_partial_match
Array(pre_registered).first
else
invalid_request! '"redirect_uri" missing'
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, :session_state, :approval
def initialize(request)
@state = request.state
super
end
def approved?
@approval
end
def approve!
@approval = true
end
def protocol_params
{state: state, session_state: session_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-2.2.1/lib/rack/oauth2/server/authorize/ 0000775 0000000 0000000 00000000000 14542752767 0022067 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/authorize/code.rb 0000664 0000000 0000000 00000001565 14542752767 0023335 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/authorize/error.rb 0000664 0000000 0000000 00000006315 14542752767 0023552 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/authorize/extension.rb 0000664 0000000 0000000 00000000427 14542752767 0024433 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/authorize/extension/ 0000775 0000000 0000000 00000000000 14542752767 0024103 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/authorize/extension/code_and_token.rb 0000664 0000000 0000000 00000001770 14542752767 0027371 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/authorize/token.rb 0000664 0000000 0000000 00000001700 14542752767 0023532 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/extension.rb 0000664 0000000 0000000 00000000140 14542752767 0022411 0 ustar 00root root 0000000 0000000 require 'rack/oauth2/server/extension/pkce'
require 'rack/oauth2/server/extension/response_mode' rack-oauth2-2.2.1/lib/rack/oauth2/server/extension/ 0000775 0000000 0000000 00000000000 14542752767 0022071 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/extension/pkce.rb 0000664 0000000 0000000 00000002565 14542752767 0023350 0 ustar 00root root 0000000 0000000 module 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&.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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/extension/response_mode.rb 0000664 0000000 0000000 00000000645 14542752767 0025265 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
module Server
module Extension
module ResponseMode
module AuthorizationRequest
def self.included(klass)
klass.send :attr_optional, :response_mode
end
def initialize(env)
super
@response_mode = params['response_mode']
end
end
end
end
end
end
end rack-oauth2-2.2.1/lib/rack/oauth2/server/rails.rb 0000664 0000000 0000000 00000000465 14542752767 0021521 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/rails/ 0000775 0000000 0000000 00000000000 14542752767 0021167 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/rails/authorize.rb 0000664 0000000 0000000 00000002030 14542752767 0023521 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/rails/response_ext.rb 0000664 0000000 0000000 00000001477 14542752767 0024243 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
module Server
module Rails
module ResponseExt
def redirect?
ensure_finish do
super
end
end
def location
ensure_finish do
super
end
end
def json
ensure_finish do
@body
end
end
def headers
ensure_finish do
@headers
end
end
def finish
@finished = true
super
end
private
def finished?
!!@finished
end
def ensure_finish
@status, @headers, @body = finish unless finished?
yield
end
end
end
end
end
end
rack-oauth2-2.2.1/lib/rack/oauth2/server/resource.rb 0000664 0000000 0000000 00000002353 14542752767 0022234 0 ustar 00root root 0000000 0000000 module 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'
rack-oauth2-2.2.1/lib/rack/oauth2/server/resource/ 0000775 0000000 0000000 00000000000 14542752767 0021704 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/resource/bearer.rb 0000664 0000000 0000000 00000002304 14542752767 0023470 0 ustar 00root root 0000000 0000000 module 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-2.2.1/lib/rack/oauth2/server/resource/bearer/ 0000775 0000000 0000000 00000000000 14542752767 0023144 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/resource/bearer/error.rb 0000664 0000000 0000000 00000001045 14542752767 0024622 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/resource/error.rb 0000664 0000000 0000000 00000005324 14542752767 0023366 0 ustar 00root root 0000000 0000000 module 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
headers = response.headers['WWW-Authenticate'] = "#{scheme} realm=\"#{realm}\""
if ErrorMethods::DEFAULT_DESCRIPTION.keys.include?(error)
headers << ", error=\"#{error}\""
headers << ", error_description=\"#{description}\"" if description.present?
headers << ", 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-2.2.1/lib/rack/oauth2/server/token.rb 0000664 0000000 0000000 00000006103 14542752767 0021522 0 ustar 00root root 0000000 0000000 require '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, :client_assertion, :client_assertion_type
def initialize(env)
auth = Rack::Auth::Basic::Request.new(env)
if auth.provided? && auth.basic?
@client_id, @client_secret = auth.credentials.map do |cred|
Util.www_form_url_decode cred
end
super
else
super
@client_secret = params['client_secret']
@client_assertion = params['client_assertion']
@client_assertion_type = params['client_assertion_type']
if client_assertion.present? && client_assertion_type == URN::ClientAssertionType::JWT_BEARER
require 'json/jwt'
@client_id = JSON::JWT.decode(
client_assertion,
:skip_verification
)[:sub] rescue nil
end
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 Util.compact_hash(protocol_params).to_json
headers['Content-Type'] = 'application/json'
headers['Cache-Control'] = 'no-store'
headers['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-2.2.1/lib/rack/oauth2/server/token/ 0000775 0000000 0000000 00000000000 14542752767 0021175 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/token/authorization_code.rb 0000664 0000000 0000000 00000001333 14542752767 0025414 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/client_credentials.rb 0000664 0000000 0000000 00000000763 14542752767 0025363 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/error.rb 0000664 0000000 0000000 00000004727 14542752767 0022665 0 ustar 00root root 0000000 0000000 module Rack
module OAuth2
module Server
class Token
class BadRequest < Abstract::BadRequest
end
class Unauthorized < Abstract::Unauthorized
def finish
super do |response|
unless @skip_www_authenticate
response.headers['WWW-Authenticate'] = 'Basic realm="OAuth2 Token Endpoint"'
end
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-2.2.1/lib/rack/oauth2/server/token/extension.rb 0000664 0000000 0000000 00000000426 14542752767 0023540 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/extension/ 0000775 0000000 0000000 00000000000 14542752767 0023211 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/lib/rack/oauth2/server/token/extension/example.rb 0000664 0000000 0000000 00000001604 14542752767 0025172 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/jwt_bearer.rb 0000664 0000000 0000000 00000001152 14542752767 0023645 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/password.rb 0000664 0000000 0000000 00000001156 14542752767 0023367 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/refresh_token.rb 0000664 0000000 0000000 00000001115 14542752767 0024356 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/server/token/saml2_bearer.rb 0000664 0000000 0000000 00000001156 14542752767 0024063 0 ustar 00root root 0000000 0000000 module 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
end rack-oauth2-2.2.1/lib/rack/oauth2/urn.rb 0000664 0000000 0000000 00000001533 14542752767 0017702 0 ustar 00root root 0000000 0000000 module 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' # RFC8693
REFRESH_TOKEN = 'urn:ietf:params:oauth:token-type:refresh_token' # RFC8693
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' # RFC8693
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
end rack-oauth2-2.2.1/lib/rack/oauth2/util.rb 0000664 0000000 0000000 00000003260 14542752767 0020052 0 ustar 00root root 0000000 0000000 require 'base64'
module Rack
module OAuth2
module Util
class << self
def www_form_url_encode(text)
URI.encode_www_form_component(text)
end
def www_form_url_decode(text)
URI.decode_www_form_component(text)
end
def base64_encode(text)
Base64.encode64(text).delete("\n")
end
def urlsafe_base64_encode(text)
Base64.urlsafe_encode64(text, padding: false)
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
encoded_response_params = Util.compact_hash(params).to_query.gsub('+', '%20')
case location
when :query
redirect_uri.query = [redirect_uri.query, encoded_response_params].compact.join('&')
when :fragment
redirect_uri.fragment = encoded_response_params
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
end
rack-oauth2-2.2.1/rack-oauth2.gemspec 0000664 0000000 0000000 00000002334 14542752767 0017346 0 ustar 00root root 0000000 0000000 Gem::Specification.new do |s|
s.name = 'rack-oauth2'
s.version = File.read('VERSION')
s.authors = ['nov matake']
s.description = %q{OAuth 2.0 Server & Client Library. Both Bearer token type are supported.}
s.summary = %q{OAuth 2.0 Server & Client Library - Both Bearer token type are supported}
s.email = 'nov@matake.jp'
s.extra_rdoc_files = ['LICENSE', 'README.rdoc']
s.rdoc_options = ['--charset=UTF-8']
s.homepage = 'https://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', '>= 2.1.0'
s.add_runtime_dependency 'faraday', '~> 2.0'
s.add_runtime_dependency 'faraday-follow_redirects'
s.add_runtime_dependency 'activesupport'
s.add_runtime_dependency 'attr_required'
s.add_runtime_dependency 'json-jwt', '>= 1.11.0'
s.add_development_dependency 'rake'
s.add_development_dependency 'simplecov'
s.add_development_dependency 'rspec'
s.add_development_dependency 'rspec-its'
s.add_development_dependency 'webmock'
s.add_development_dependency 'rexml'
end
rack-oauth2-2.2.1/spec/ 0000775 0000000 0000000 00000000000 14542752767 0014611 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/helpers/ 0000775 0000000 0000000 00000000000 14542752767 0016253 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/helpers/time.rb 0000664 0000000 0000000 00000000506 14542752767 0017537 0 ustar 00root root 0000000 0000000 class 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-2.2.1/spec/helpers/webmock_helper.rb 0000664 0000000 0000000 00000002075 14542752767 0021572 0 ustar 00root root 0000000 0000000 require '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&.[](: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 = {}
format = options[:format] || :json
if format == :json
response[:headers] = {
'Content-Type': 'application/json'
}
end
response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', "#{response_file}.#{format}"))
if options[:status]
response[:status] = options[:status]
end
response
end
end
include WebMockHelper
WebMock.disable_net_connect! rack-oauth2-2.2.1/spec/mock_response/ 0000775 0000000 0000000 00000000000 14542752767 0017460 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/mock_response/blank.txt 0000664 0000000 0000000 00000000000 14542752767 0021276 0 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/mock_response/errors/ 0000775 0000000 0000000 00000000000 14542752767 0020774 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/mock_response/errors/invalid_request.json 0000664 0000000 0000000 00000000112 14542752767 0025057 0 ustar 00root root 0000000 0000000 {
"error":"invalid_request",
"error_description":"error description"
} rack-oauth2-2.2.1/spec/mock_response/resources/ 0000775 0000000 0000000 00000000000 14542752767 0021472 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/mock_response/resources/fake.txt 0000664 0000000 0000000 00000000004 14542752767 0023133 0 ustar 00root root 0000000 0000000 fake rack-oauth2-2.2.1/spec/mock_response/tokens/ 0000775 0000000 0000000 00000000000 14542752767 0020763 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/mock_response/tokens/_Bearer.json 0000664 0000000 0000000 00000000164 14542752767 0023216 0 ustar 00root root 0000000 0000000 {
"access_token":"access_token",
"refresh_token":"refresh_token",
"token_type":"Bearer",
"expires_in":3600
} rack-oauth2-2.2.1/spec/mock_response/tokens/bearer.json 0000664 0000000 0000000 00000000164 14542752767 0023117 0 ustar 00root root 0000000 0000000 {
"access_token":"access_token",
"refresh_token":"refresh_token",
"token_type":"bearer",
"expires_in":3600
} rack-oauth2-2.2.1/spec/mock_response/tokens/unknown.json 0000664 0000000 0000000 00000000165 14542752767 0023357 0 ustar 00root root 0000000 0000000 {
"access_token":"access_token",
"refresh_token":"refresh_token",
"token_type":"unknown",
"expires_in":3600
} rack-oauth2-2.2.1/spec/rack/ 0000775 0000000 0000000 00000000000 14542752767 0015531 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/ 0000775 0000000 0000000 00000000000 14542752767 0016733 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/access_token/ 0000775 0000000 0000000 00000000000 14542752767 0021374 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/access_token/authenticator_spec.rb 0000664 0000000 0000000 00000001325 14542752767 0025606 0 ustar 00root root 0000000 0000000 require 'spec_helper'
describe Rack::OAuth2::AccessToken::Authenticator do
let(:resource_endpoint) { 'https://server.example.com/resources/fake' }
let(:request) { Faraday::Request.new(: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.authenticate(request)
end
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
end
rack-oauth2-2.2.1/spec/rack/oauth2/access_token/bearer_spec.rb 0000664 0000000 0000000 00000001074 14542752767 0024175 0 ustar 00root root 0000000 0000000 require '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) { Faraday::Request.new(:post, URI.parse(resource_endpoint), '', {hello: "world"}, {}) }
describe '.authenticate' do
it 'should set Authorization header' do
expect(request.headers).to receive(:[]=).with('Authorization', 'Bearer access_token')
token.authenticate(request)
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/access_token_spec.rb 0000664 0000000 0000000 00000003045 14542752767 0022735 0 ustar 00root root 0000000 0000000 require '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|
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-2.2.1/spec/rack/oauth2/client/ 0000775 0000000 0000000 00000000000 14542752767 0020211 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/client/error_spec.rb 0000664 0000000 0000000 00000000743 14542752767 0022705 0 ustar 00root root 0000000 0000000 require '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], error[:error_description]].join(' :: ') }
its(:response) { should == error }
end
rack-oauth2-2.2.1/spec/rack/oauth2/client/grant/ 0000775 0000000 0000000 00000000000 14542752767 0021324 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/client/grant/authorization_code_spec.rb 0000664 0000000 0000000 00000001775 14542752767 0026567 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/client/grant/client_credentials_spec.rb 0000664 0000000 0000000 00000000242 14542752767 0026514 0 ustar 00root root 0000000 0000000 require 'spec_helper.rb'
describe Rack::OAuth2::Client::Grant::ClientCredentials do
its(:as_json) do
should == {grant_type: :client_credentials}
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/client/grant/jwt_bearer_spec.rb 0000664 0000000 0000000 00000001064 14542752767 0025010 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/client/grant/password_spec.rb 0000664 0000000 0000000 00000001431 14542752767 0024524 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/client/grant/refresh_token_spec.rb 0000664 0000000 0000000 00000001015 14542752767 0025516 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/client/grant/saml2_bearer_spec.rb 0000664 0000000 0000000 00000001046 14542752767 0025222 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/client_spec.rb 0000664 0000000 0000000 00000040407 14542752767 0021555 0 ustar 00root root 0000000 0000000 require 'spec_helper.rb'
describe Rack::OAuth2::Client do
let(:client_id) { 'client_id' }
let(:client_secret) { 'client_secret' }
let :client do
Rack::OAuth2::Client.new(
identifier: client_id,
secret: client_secret,
host: 'server.example.com',
redirect_uri: 'https://client.example.com/callback',
revocation_endpoint: '/oauth2/revoke'
)
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' }
its(:revocation_endpoint) { should == '/oauth2/revoke' }
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%20code' }
end
context 'when scope is given' do
subject { client.authorization_uri(scope: [:scope1, :scope2]) }
it { should include 'scope=scope1%20scope2' }
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 '*args handling' 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',
request_header: {
'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ='
}
)
client.access_token!
end
context 'when Basic auth method is used' do
context 'when client_id is a url' do
let(:client_id) { 'https://client.example.com'}
it 'should be encoded in "application/x-www-form-urlencoded"' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
request_header: {
'Authorization' => 'Basic aHR0cHMlM0ElMkYlMkZjbGllbnQuZXhhbXBsZS5jb206Y2xpZW50X3NlY3JldA=='
}
)
client.access_token!
end
end
end
context 'when basic_without_www_form_urlencode method is used' do
context 'when client_id is a url' do
let(:client_id) { 'https://client.example.com'}
it 'should be encoded in "application/x-www-form-urlencoded"' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
request_header: {
'Authorization' => 'Basic aHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5jb206Y2xpZW50X3NlY3JldA=='
}
)
client.access_token! :basic_without_www_form_urlencode
end
end
end
context 'when jwt_bearer auth method specified' do
context 'when client_secret is given' do
it 'should be JWT bearer client assertion w/ auto-generated HS256-signed JWT assertion' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
params: {
client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\..+/, # NOTE: HS256
client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
code: 'code',
grant_type: 'authorization_code',
redirect_uri: 'https://client.example.com/callback'
}
)
client.access_token! :jwt_bearer
end
end
context 'when private_key is given' do
context 'when RSA key' do
let :client do
Rack::OAuth2::Client.new(
identifier: 'client_id',
private_key: OpenSSL::PKey::RSA.generate(2048),
host: 'server.example.com',
redirect_uri: 'https://client.example.com/callback'
)
end
it 'should be JWT bearer client assertion w/ auto-generated RS256-signed JWT assertion' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
params: {
client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9\..+/, # NOTE: RS256
client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
code: 'code',
grant_type: 'authorization_code',
redirect_uri: 'https://client.example.com/callback'
}
)
client.access_token! :jwt_bearer
end
end
context 'when EC key' do
let :client do
Rack::OAuth2::Client.new(
identifier: 'client_id',
private_key: OpenSSL::PKey::EC.generate('prime256v1'),
host: 'server.example.com',
redirect_uri: 'https://client.example.com/callback'
)
end
it 'should be JWT bearer client assertion w/ auto-generated ES256-signed JWT assertion' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
params: {
client_assertion: /^eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9\..+/, # NOTE: ES256
client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
code: 'code',
grant_type: 'authorization_code',
redirect_uri: 'https://client.example.com/callback'
}
)
client.access_token! :jwt_bearer
end
end
end
context 'when client_assertion is explicitly given' do
let :client do
Rack::OAuth2::Client.new(
identifier: 'client_id',
host: 'server.example.com',
redirect_uri: 'https://client.example.com/callback'
)
end
it 'should be JWT bearer client assertion w/ specified assertion' do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
params: {
client_assertion: 'any.jwt.assertion',
client_assertion_type: Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER,
code: 'code',
grant_type: 'authorization_code',
redirect_uri: 'https://client.example.com/callback'
}
)
client.access_token! :jwt_bearer, client_assertion: 'any.jwt.assertion'
end
end
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',
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',
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',
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',
params: {
grant_type: 'client_credentials',
resource: 'something'
}
)
client.access_token! resource: :something
end
end
end
context 'local_http_config handling' do
it do
mock_response(
:post,
'https://server.example.com/oauth2/token',
'tokens/bearer',
request_header: {
'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=',
'X-Foo' => 'bar'
}
)
client.access_token! do |request|
request.headers['X-Foo'] = 'bar'
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'
)
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'
)
end
it { should be_instance_of Rack::OAuth2::AccessToken::Bearer }
its(:token_type) { should == :bearer }
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'
)
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',
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',
format: 'txt',
status: 400
)
end
it do
expect { client.access_token! }.to raise_error Rack::OAuth2::Client::Error
end
end
end
end
describe '#revoke!' do
context 'local_http_config handling' do
it do
mock_response(
:post,
'https://server.example.com/oauth2/revoke',
'blank',
format: 'txt',
status: 200,
body: {
token: 'access_token',
token_type_hint: 'access_token'
},
request_header: {
'Authorization' => 'Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=',
'X-Foo' => 'bar'
}
)
client.revoke!(access_token: 'access_token') do |request|
request.headers['X-Foo'] = 'bar'
end
end
end
context 'when access_token given' do
before do
mock_response(
:post,
'https://server.example.com/oauth2/revoke',
'blank',
format: 'txt',
status: 200,
body: {
token: 'access_token',
token_type_hint: 'access_token'
}
)
end
it do
client.revoke!(access_token: 'access_token').should == :success
end
end
context 'when refresh_token given' do
before do
mock_response(
:post,
'https://server.example.com/oauth2/revoke',
'blank',
format: 'txt',
status: 200,
body: {
token: 'refresh_token',
token_type_hint: 'refresh_token'
}
)
end
context 'as argument' do
it do
client.revoke!(refresh_token: 'refresh_token').should == :success
end
end
context 'as grant' do
it do
client.refresh_token = 'refresh_token'
client.revoke!
end
end
end
context 'when error response given' do
before do
mock_response(
:post,
'https://server.example.com/oauth2/revoke',
'errors/invalid_request',
status: 400
)
end
it do
expect do
client.revoke! access_token: 'access_token'
end.to raise_error Rack::OAuth2::Client::Error
end
end
context 'when no token given' do
it do
expect do
client.revoke!
end.to raise_error ArgumentError
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',
revocation_endpoint: '/oauth2/revoke'
)
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
describe '#revoke!' do
it do
expect { client.revoke! access_token: 'access_token' }.to raise_error 'No Host Info'
end
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/oauth2_spec.rb 0000664 0000000 0000000 00000001345 14542752767 0021477 0 ustar 00root root 0000000 0000000 require '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
end rack-oauth2-2.2.1/spec/rack/oauth2/server/ 0000775 0000000 0000000 00000000000 14542752767 0020241 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/abstract/ 0000775 0000000 0000000 00000000000 14542752767 0022044 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/abstract/error_spec.rb 0000664 0000000 0000000 00000003306 14542752767 0024536 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/authorize/ 0000775 0000000 0000000 00000000000 14542752767 0022253 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/authorize/code_spec.rb 0000664 0000000 0000000 00000003645 14542752767 0024534 0 ustar 00root root 0000000 0000000 require '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.gsub('+', '%20')}&state=state"
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/authorize/error_spec.rb 0000664 0000000 0000000 00000007445 14542752767 0024755 0 ustar 00root root 0000000 0000000 require '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, headers, response = error.finish
state.should == 302
headers["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, headers, response = error.finish
state.should == 302
headers["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, headers, response = error.finish
state.should == 302
headers["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-2.2.1/spec/rack/oauth2/server/authorize/extensions/ 0000775 0000000 0000000 00000000000 14542752767 0024452 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/authorize/extensions/code_and_token_spec.rb 0000664 0000000 0000000 00000004333 14542752767 0030750 0 ustar 00root root 0000000 0000000 require '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.gsub('+', '%20')}"
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/authorize/token_spec.rb 0000664 0000000 0000000 00000004620 14542752767 0024734 0 ustar 00root root 0000000 0000000 require '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.gsub('+', '%20')}&state=state"
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/authorize_spec.rb 0000664 0000000 0000000 00000015177 14542752767 0023625 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/extension/ 0000775 0000000 0000000 00000000000 14542752767 0022255 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/extension/pkce_spec.rb 0000664 0000000 0000000 00000012206 14542752767 0024537 0 ustar 00root root 0000000 0000000 require '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(:code_verifier) { SecureRandom.hex(16) }
let(:code_challenge) { Base64.urlsafe_encode64(OpenSSL::Digest::SHA256.digest(code_verifier)).delete('=') }
let(:code_challenge_method) { :S256 }
subject { @request }
describe 'authorization request' do
let :app do
Rack::OAuth2::Server::Authorize.new do |request, response|
@request = request
end
end
context 'when code_challenge is given' do
context 'when code_challenge_method is given' do
before do
request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state&code_challenge=#{code_challenge}&code_challenge_method=#{code_challenge_method}"
end
its(:code_challenge) { should == code_challenge }
its(:code_challenge_method) { should == code_challenge_method.to_s }
end
context 'when code_challenge_method is omitted' do
before do
request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state&code_challenge=#{code_challenge}"
end
its(:code_challenge) { should == code_challenge }
its(:code_challenge_method) { should == nil }
end
end
context 'otherwise' do
before do
request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state"
end
its(:code_challenge) { should == nil }
its(:code_challenge_method) { should == nil }
end
end
describe 'token request' do
let(:app) do
Rack::OAuth2::Server::Token.new do |request, response|
@request = request
response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token')
end
end
let(:default_params) do
{
grant_type: 'authorization_code',
client_id: 'client_id',
client_secret: 'client_secret',
code: 'authorization_code',
redirect_uri: 'http://client.example.com/callback'
}
end
context 'when code_verifier is given' do
before do
request.post '/', params: default_params.merge(
code_verifier: code_verifier
)
end
its(:code_verifier) { should == code_verifier }
describe '#verify_code_verifier!' do
context 'when code_verifier is given with code_challenge_method=plain' do
it do
expect do
subject.verify_code_verifier! code_verifier, :plain
end.not_to raise_error
end
end
context 'when collect code_challenge is given' do
it do
expect do
subject.verify_code_verifier! code_challenge
end.not_to raise_error
end
end
context 'when wrong code_challenge is blank' do
it do
expect do
subject.verify_code_verifier! 'wrong'
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
context 'when code_challenge is nil' do
it do
expect do
subject.verify_code_verifier! nil
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
context 'when unknown code_challenge_method is given' do
it do
expect do
subject.verify_code_verifier! code_challenge, :unknown
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
end
end
context 'otherwise' do
before do
request.post '/', params: default_params
end
its(:code_verifier) { should == nil }
describe '#verify_code_verifier!' do
context 'when code_verifier is given with code_challenge_method=plain' do
it do
expect do
subject.verify_code_verifier! code_verifier, :plain
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
context 'when collect code_challenge is given' do
it do
expect do
subject.verify_code_verifier! code_challenge
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
context 'when wrong code_challenge is blank' do
it do
expect do
subject.verify_code_verifier! 'wrong'
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
context 'when code_challenge is nil' do
it do
expect do
subject.verify_code_verifier! nil
end.not_to raise_error
end
end
context 'when unknown code_challenge_method is given' do
it do
expect do
subject.verify_code_verifier! code_challenge, :unknown
end.to raise_error Rack::OAuth2::Server::Token::BadRequest, /invalid_grant/
end
end
end
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/extension/response_mode_spec.rb 0000664 0000000 0000000 00000001600 14542752767 0026453 0 ustar 00root root 0000000 0000000 require '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(:response_mode) { 'form_post' }
subject { @request }
describe 'authorization request' do
let :app do
Rack::OAuth2::Server::Authorize.new do |request, response|
@request = request
end
end
context 'when response_mode is given' do
before do
request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state&response_mode=#{response_mode}"
end
its(:response_mode) { should == response_mode }
end
context 'otherwise' do
before do
request.get "/?response_type=code&client_id=client&redirect_uri=#{redirect_uri}&state=state"
end
its(:response_mode) { should == nil }
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/resource/ 0000775 0000000 0000000 00000000000 14542752767 0022070 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/resource/bearer/ 0000775 0000000 0000000 00000000000 14542752767 0023330 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/resource/bearer/error_spec.rb 0000664 0000000 0000000 00000003406 14542752767 0026023 0 ustar 00root root 0000000 0000000 require '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, headers, response = error.finish
headers['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
end rack-oauth2-2.2.1/spec/rack/oauth2/server/resource/bearer_spec.rb 0000664 0000000 0000000 00000007647 14542752767 0024705 0 ustar 00root root 0000000 0000000 require '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, headers, 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, headers, response = request
status.should == 401
headers['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, headers, 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, headers, 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, headers, response = request
headers['WWW-Authenticate'].should include "Bearer realm=\"#{realm}\""
end
end
context 'otherwize' do
it 'should use default realm' do
status, headers, response = request
headers['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-2.2.1/spec/rack/oauth2/server/resource/error_spec.rb 0000664 0000000 0000000 00000012706 14542752767 0024566 0 ustar 00root root 0000000 0000000 require '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, headers, response = error.finish
status.should == 400
headers['Content-Type'].should == 'application/json'
response.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, headers, response = error_with_scheme.finish
status.should == 401
headers['Content-Type'].should == 'application/json'
headers['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\", error=\"invalid_token\""
response.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, headers, response = error_with_scheme.finish
headers['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\""
response.first.should include '"error":"something"'
end
end
context 'when no error_code is given' do
let(:error) { Rack::OAuth2::Server::Resource::Unauthorized.new }
it 'should have error_code in body but not in WWW-Authenticate header' do
status, headers, response = error_with_scheme.finish
headers['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\""
response.first.should == '{"error":"unauthorized"}'
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, headers, response = error_with_scheme.finish
headers['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\""
response.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, headers, response = error.finish
status.should == 403
headers['Content-Type'].should == 'application/json'
response.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, headers, response = error.finish
response.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-2.2.1/spec/rack/oauth2/server/resource_spec.rb 0000664 0000000 0000000 00000001153 14542752767 0023427 0 ustar 00root root 0000000 0000000 require '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
end rack-oauth2-2.2.1/spec/rack/oauth2/server/token/ 0000775 0000000 0000000 00000000000 14542752767 0021361 5 ustar 00root root 0000000 0000000 rack-oauth2-2.2.1/spec/rack/oauth2/server/token/authorization_code_spec.rb 0000664 0000000 0000000 00000002505 14542752767 0026614 0 ustar 00root root 0000000 0000000 require '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.headers['Cache-Control'].should == 'no-store'
response.headers['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-2.2.1/spec/rack/oauth2/server/token/client_credentials_spec.rb 0000664 0000000 0000000 00000003132 14542752767 0026552 0 ustar 00root root 0000000 0000000 require '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|
unless request.client_id == client_id && request.client_secret == client_secret
request.invalid_client!
end
response.access_token = Rack::OAuth2::AccessToken::Bearer.new(access_token: 'access_token')
end
end
let(:client_id) { 'client_id '}
let(:client_secret) { 'client_secret' }
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"' }
context 'basic auth' do
let(:params) do
{ grant_type: 'client_credentials' }
end
let(:encoded_creds) do
Base64.strict_encode64([
Rack::OAuth2::Util.www_form_url_encode(client_id),
Rack::OAuth2::Util.www_form_url_encode(client_secret)
].join(':'))
end
subject do
request.post('/',
{params: params, 'HTTP_AUTHORIZATION' => "Basic #{encoded_creds}"})
end
its(:status) { should == 200 }
context 'compliance with RFC6749 sec 2.3.1' do
let(:client_id) { 'client: yes/please!' }
let(:client_secret) { 'terrible:secret:of:space' }
its(:status) { should == 200 }
end
end
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/token/error_spec.rb 0000664 0000000 0000000 00000005316 14542752767 0024056 0 ustar 00root root 0000000 0000000 require '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, headers, response = error.finish
status.should == 400
headers['Content-Type'].should == 'application/json'
response.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, headers, response = error.finish
status.should == 401
headers['Content-Type'].should == 'application/json'
headers['WWW-Authenticate'].should == 'Basic realm="OAuth2 Token Endpoint"'
response.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
end
rack-oauth2-2.2.1/spec/rack/oauth2/server/token/jwt_bearer_spec.rb 0000664 0000000 0000000 00000002066 14542752767 0025050 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/token/password_spec.rb 0000664 0000000 0000000 00000002134 14542752767 0024562 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/token/refresh_token_spec.rb 0000664 0000000 0000000 00000002034 14542752767 0025555 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/token/saml2_bearer_spec.rb 0000664 0000000 0000000 00000002060 14542752767 0025254 0 ustar 00root root 0000000 0000000 require '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-2.2.1/spec/rack/oauth2/server/token_spec.rb 0000664 0000000 0000000 00000014170 14542752767 0022723 0 ustar 00root root 0000000 0000000 require '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, headers, response = app.call(env)
status.should == 400
response.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, headers, 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
context 'when client_id is given via JWT client assertion' do
before do
require 'json/jwt'
params[:client_assertion] = JSON::JWT.new(
sub: params[:client_id]
# NOTE: actual client_assertion should have more claims.
).sign('client_secret').to_s
params[:client_assertion_type] = Rack::OAuth2::URN::ClientAssertionType::JWT_BEARER
params.delete(:client_id)
end
context 'when client_assertion is invalid JWT' do
before do
params[:client_assertion] = 'invalid-jwt'
end
its(:status) { should == 400 }
its(:content_type) { should == 'application/json' }
its(:body) { should include '"error":"invalid_request"' }
end
context 'when client_assertion_type is missing' do
before do
params.delete(:client_assertion_type)
end
its(:status) { should == 400 }
its(:content_type) { should == 'application/json' }
its(:body) { should include '"error":"invalid_request"' }
end
context 'when client_assertion_type is unknown' do
before do
params[:client_assertion_type] = 'unknown'
end
its(:status) { should == 400 }
its(:content_type) { should == 'application/json' }
its(:body) { should include '"error":"invalid_request"' }
end
context 'when client_assertion issuer is different from client_id' do
before do
params[:client_id] = 'another_client_id'
end
its(:status) { should == 400 }
its(:content_type) { should == 'application/json' }
its(:body) { should include '"error":"invalid_request"' }
end
context 'otherwise' do
its(:status) { should == 200 }
its(:content_type) { should == 'application/json' }
its(:body) { should include '"access_token":"access_token"' }
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}\"" }
if error == :invalid_client
its(:headers) { should include 'WWW-Authenticate' }
end
end
end
context 'when skip_www_authenticate option is specified on invalid_client' do
let(:app) do
Rack::OAuth2::Server::Token.new do |request, response|
request.invalid_client!(
Rack::OAuth2::Server::Token::ErrorMethods::DEFAULT_DESCRIPTION[:invalid_client],
skip_www_authenticate: true
)
end
end
its(:headers) { should_not include 'WWW-Authenticate' }
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-2.2.1/spec/rack/oauth2/util_spec.rb 0000664 0000000 0000000 00000005062 14542752767 0021252 0 ustar 00root root 0000000 0000000 require '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 '.www_form_url_encode' do
subject { util.www_form_url_encode '=+ .-/' }
it { should == '%3D%2B+.-%2F' }
end
describe '.www_form_urldecode' do
subject { util.www_form_url_decode '%3D%2B+.-%2F' }
it { should == '=+ .-/' }
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-2.2.1/spec/spec_helper.rb 0000664 0000000 0000000 00000000605 14542752767 0017430 0 ustar 00root root 0000000 0000000 require '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