7 Commits
1.5.1 ... 1.6.0

Author SHA1 Message Date
domaindrivendev
c8e9ab3221 Add puma to Gemfile to fix integration tests 2018-04-23 16:24:43 -07:00
domaindrivendev
26a3bf5079 avoid metadata mutation in request_factory 2018-04-23 16:00:07 -07:00
Richard Morris
12daacf9a5 Merge pull request #112 from akurashev/master
Fix Authorization header missing and duplicating
2018-04-23 15:49:32 -07:00
Andrey Kurashev
05e1e2271f Fix Authorization header missing and duplicating 2018-02-20 14:49:13 +06:00
domaindrivendev
07ae261e54 Bump ruby patch version 2017-10-21 14:25:12 -07:00
domaindrivendev
06d00de992 Assume symbol for referenced parameter key 2017-09-06 13:38:36 -07:00
domaindrivendev
ad9cd5de66 Support paired security requirements - e.g. basic and apiKey 2017-08-21 01:07:47 -07:00
11 changed files with 184 additions and 49 deletions

View File

@@ -1 +1 @@
2.3.0
2.3.1

View File

@@ -28,6 +28,7 @@ group :test do
gem 'generator_spec'
gem 'capybara'
gem 'capybara-webkit'
gem 'puma'
end
group :assets do

View File

@@ -29,28 +29,27 @@ module Rswag
path_item_params = metadata[:path_item][:parameters] || []
security_params = derive_security_params(metadata, swagger_doc)
operation_params
.concat(path_item_params)
.concat(security_params)
# NOTE: Use of + instead of concat to avoid mutation of the metadata object
(operation_params + path_item_params + security_params)
.map { |p| p['$ref'] ? resolve_parameter(p['$ref'], swagger_doc) : p }
.uniq { |p| p[:name] }
.reject { |p| p[:required] == false && !example.respond_to?(p[:name]) }
end
def derive_security_params(metadata, swagger_doc)
requirements = metadata[:operation][:security] || swagger_doc[:security]
scheme_names = requirements ? requirements.map { |r| r.keys.first } : []
applicable_schemes = (swagger_doc[:securityDefinitions] || {}).slice(*scheme_names).values
requirements = metadata[:operation][:security] || swagger_doc[:security] || []
scheme_names = requirements.flat_map { |r| r.keys }
schemes = (swagger_doc[:securityDefinitions] || {}).slice(*scheme_names).values
applicable_schemes.map do |scheme|
schemes.map do |scheme|
param = (scheme[:type] == :apiKey) ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header }
param.merge(type: :string)
param.merge(type: :string, required: requirements.one?)
end
end
def resolve_parameter(ref, swagger_doc)
key = ref.sub('#/parameters/', '').to_sym
definitions = swagger_doc[:parameters]
key = ref.sub('#/parameters/', '')
raise "Referenced parameter '#{ref}' must be defined" unless definitions && definitions[key]
definitions[key]
end

View File

@@ -201,6 +201,18 @@ module Rswag
end
end
context 'basic auth' do
before do
swagger_doc[:securityDefinitions] = { basic: { type: :basic } }
metadata[:operation][:security] = [ basic: [] ]
allow(example).to receive(:Authorization).and_return('Basic foobar')
end
it "sets 'HTTP_AUTHORIZATION' header to example value" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
end
end
context 'apiKey' do
before do
swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: key_location } }
@@ -223,17 +235,22 @@ module Rswag
expect(request[:headers]).to eq('api_key' => 'foobar')
end
end
end
context 'basic auth' do
before do
swagger_doc[:securityDefinitions] = { basic: { type: :basic } }
metadata[:operation][:security] = [ basic: [] ]
allow(example).to receive(:Authorization).and_return('Basic foobar')
end
context 'in header with auth param already added' do
let(:key_location) { :header }
before do
metadata[:operation][:parameters] = [
{ name: 'q1', in: :query, type: :string },
{ name: 'api_key', in: :header, type: :string }
]
allow(example).to receive(:q1).and_return('foo')
allow(example).to receive(:api_key).and_return('foobar')
end
it "sets 'HTTP_AUTHORIZATION' header to example value" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
it 'adds authorization parameter only once' do
expect(request[:headers]).to eq('api_key' => 'foobar')
expect(metadata[:operation][:parameters].size).to eq 2
end
end
end
@@ -249,6 +266,23 @@ module Rswag
end
end
context 'paired security requirements' do
before do
swagger_doc[:securityDefinitions] = {
basic: { type: :basic },
api_key: { type: :apiKey, name: 'api_key', in: :query }
}
metadata[:operation][:security] = [ { basic: [], api_key: [] } ]
allow(example).to receive(:Authorization).and_return('Basic foobar')
allow(example).to receive(:api_key).and_return('foobar')
end
it "sets both params to example values" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
expect(request[:path]).to eq('/blogs?api_key=foobar')
end
end
context "path-level parameters" do
before do
metadata[:operation][:parameters] = [ { name: 'q1', in: :query, type: :string } ]
@@ -264,7 +298,7 @@ module Rswag
context 'referenced parameters' do
before do
swagger_doc[:parameters] = { 'q1' => { name: 'q1', in: :query, type: :string } }
swagger_doc[:parameters] = { q1: { name: 'q1', in: :query, type: :string } }
metadata[:operation][:parameters] = [ { '$ref' => '#/parameters/q1' } ]
allow(example).to receive(:q1).and_return('foo')
end

View File

@@ -2,10 +2,29 @@ class AuthTestsController < ApplicationController
# POST /auth-tests/basic
def basic
if authenticate_with_http_basic { |u, p| u == 'jsmith' && p == 'jspass' }
head :no_content
else
request_http_basic_authentication
end
return head :unauthorized unless authenticate_basic
head :no_content
end
# POST /auth-tests/api-key
def api_key
return head :unauthorized unless authenticate_api_key
head :no_content
end
# POST /auth-tests/basic-and-api-key
def basic_and_api_key
return head :unauthorized unless authenticate_basic and authenticate_api_key
head :no_content
end
private
def authenticate_basic
authenticate_with_http_basic { |u, p| u == 'jsmith' && p == 'jspass' }
end
def authenticate_api_key
params['api_key'] == 'foobar'
end
end

View File

@@ -3,6 +3,8 @@ TestApp::Application.routes.draw do
put '/blogs/:id/upload', to: 'blogs#upload'
post 'auth-tests/basic', to: 'auth_tests#basic'
post 'auth-tests/api-key', to: 'auth_tests#api_key'
post 'auth-tests/basic-and-api-key', to: 'auth_tests#basic_and_api_key'
mount Rswag::Api::Engine => 'api-docs'
mount Rswag::Ui::Engine => 'api-docs'

View File

@@ -1,3 +1,4 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
@@ -8,16 +9,16 @@
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(version: 20160218212104) do
ActiveRecord::Schema.define(:version => 20160218212104) do
create_table "blogs", force: :cascade do |t|
t.string "title"
t.text "content"
t.string "thumbnail"
t.datetime "created_at"
t.datetime "updated_at"
create_table "blogs", :force => true do |t|
t.string "title"
t.text "content"
t.string "thumbnail"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
end

View File

@@ -4,7 +4,7 @@ describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do
path '/auth-tests/basic' do
post 'Authenticates with basic auth' do
tags 'Auth Test'
tags 'Auth Tests'
operationId 'testBasicAuth'
security [ basic_auth: [] ]
@@ -19,4 +19,42 @@ describe 'Auth Tests API', type: :request, swagger_doc: 'v1/swagger.json' do
end
end
end
path '/auth-tests/api-key' do
post 'Authenticates with an api key' do
tags 'Auth Tests'
operationId 'testApiKey'
security [ api_key: [] ]
response '204', 'Valid credentials' do
let(:api_key) { 'foobar' }
run_test!
end
response '401', 'Invalid credentials' do
let(:api_key) { 'barfoo' }
run_test!
end
end
end
path '/auth-tests/basic-and-api-key' do
post 'Authenticates with basic auth and api key' do
tags 'Auth Tests'
operationId 'testBasicAndApiKey'
security [ { basic_auth: [], api_key: [] } ]
response '204', 'Valid credentials' do
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
let(:api_key) { 'foobar' }
run_test!
end
response '401', 'Invalid credentials' do
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
let(:api_key) { 'barfoo' }
run_test!
end
end
end
end

View File

@@ -91,7 +91,7 @@ describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
let(:id) { blog.id }
let(:blog) { Blog.create(title: 'foo', content: 'bar') }
put 'upload a blog thumbnail' do
put 'Uploads a blog thumbnail' do
tags 'Blogs'
description 'Upload a thumbnail for specific blog by id'
operationId 'uploadThumbnailBlog'

View File

@@ -54,10 +54,7 @@ RSpec.configure do |config|
name: 'api_key',
in: :query
}
},
security: [
{ api_key: [] }
]
}
}
}
end

View File

@@ -9,7 +9,7 @@
"post": {
"summary": "Authenticates with basic auth",
"tags": [
"Auth Test"
"Auth Tests"
],
"operationId": "testBasicAuth",
"security": [
@@ -29,6 +29,57 @@
}
}
},
"/auth-tests/api-key": {
"post": {
"summary": "Authenticates with an api key",
"tags": [
"Auth Tests"
],
"operationId": "testApiKey",
"security": [
{
"api_key": [
]
}
],
"responses": {
"204": {
"description": "Valid credentials"
},
"401": {
"description": "Invalid credentials"
}
}
}
},
"/auth-tests/basic-and-api-key": {
"post": {
"summary": "Authenticates with basic auth and api key",
"tags": [
"Auth Tests"
],
"operationId": "testBasicAndApiKey",
"security": [
{
"basic_auth": [
],
"api_key": [
]
}
],
"responses": {
"204": {
"description": "Valid credentials"
},
"401": {
"description": "Invalid credentials"
}
}
}
},
"/blogs": {
"post": {
"summary": "Creates a blog",
@@ -149,7 +200,7 @@
}
],
"put": {
"summary": "upload a blog thumbnail",
"summary": "Uploads a blog thumbnail",
"tags": [
"Blogs"
],
@@ -226,12 +277,5 @@
"name": "api_key",
"in": "query"
}
},
"security": [
{
"api_key": [
]
}
]
}
}