Skip to content

Commit 3d66c50

Browse files
authored
Merge pull request #1159 from shockey/ft/oas3-authorization
OAS 3.0 Authorization
2 parents f335956 + fc8da12 commit 3d66c50

File tree

6 files changed

+707
-3
lines changed

6 files changed

+707
-3
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"dependencies": {
6464
"babel-runtime": "^6.23.0",
6565
"btoa": "1.1.2",
66+
"cookie": "^0.3.1",
6667
"deep-extend": "^0.4.1",
6768
"fast-json-patch": "1.1.8",
6869
"isomorphic-fetch": "2.2.1",

src/execute/index.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import isPlainObject from 'lodash/isPlainObject'
44
import isArray from 'lodash/isArray'
55
import btoa from 'btoa'
66
import url from 'url'
7+
import cookie from 'cookie'
78
import http, {mergeInQueryOrForm} from '../http'
89
import createError from '../specmap/lib/create-error'
910

@@ -109,7 +110,8 @@ export function buildRequest(options) {
109110
// This breaks CORSs... removing this line... probably breaks oAuth. Need to address that
110111
// This also breaks tests
111112
// 'access-control-allow-origin': '*'
112-
}
113+
},
114+
cookies: {}
113115
}
114116

115117
if (requestInterceptor) {
@@ -124,6 +126,11 @@ export function buildRequest(options) {
124126

125127
// Mostly for testing
126128
if (!operationId) {
129+
// Not removing req.cookies causes testing issues and would
130+
// change our interface, so we're always sure to remove it.
131+
// See the same statement lower down in this function for
132+
// more context.
133+
delete req.cookies
127134
return req
128135
}
129136

@@ -198,6 +205,26 @@ export function buildRequest(options) {
198205
req = swagger2BuildRequest(versionSpecificOptions, req)
199206
}
200207

208+
209+
// If the cookie convenience object exists in our request,
210+
// serialize its content and then delete the cookie object.
211+
if (req.cookies && Object.keys(req.cookies).length) {
212+
const cookieString = Object.keys(req.cookies).reduce((prev, cookieName) => {
213+
const cookieValue = req.cookies[cookieName]
214+
const prefix = prev ? '&' : ''
215+
const stringified = cookie.serialize(cookieName, cookieValue)
216+
return prev + prefix + stringified
217+
}, '')
218+
req.headers.Cookie = cookieString
219+
}
220+
221+
if (req.cookies) {
222+
// even if no cookies were defined, we need to remove
223+
// the cookies key from our request, or many many legacy
224+
// tests will break.
225+
delete req.cookies
226+
}
227+
201228
// Will add the query object into the URL, if it exists
202229
// ... will also create a FormData instance, if multipart/form-data (eg: a file)
203230
mergeInQueryOrForm(req)

src/execute/oas3/build-request.js

+78-1
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
// This function runs after the common function,
22
// `src/execute/index.js#buildRequest`
3+
import assign from 'lodash/assign'
4+
import get from 'lodash/get'
5+
import btoa from 'btoa'
36

47
export default function (options, req) {
58
const {
69
operation,
7-
requestBody
10+
requestBody,
11+
securities,
12+
spec
813
} = options
914

1015
let {
1116
requestContentType
1217
} = options
1318

19+
req = applySecurities({request: req, securities, operation, spec})
20+
1421
const requestBodyDef = operation.requestBody || {}
1522
const requestBodyMediaTypes = Object.keys(requestBodyDef.content || {})
1623

@@ -64,3 +71,73 @@ export default function (options, req) {
6471

6572
return req
6673
}
74+
75+
// Add security values, to operations - that declare their need on them
76+
// Adapted from the Swagger2 implementation
77+
export function applySecurities({request, securities = {}, operation = {}, spec}) {
78+
const result = assign({}, request)
79+
const {authorized = {}} = securities
80+
const security = operation.security || spec.security || []
81+
const isAuthorized = authorized && !!Object.keys(authorized).length
82+
const securityDef = get(spec, ['components', 'securitySchemes']) || {}
83+
84+
result.headers = result.headers || {}
85+
result.query = result.query || {}
86+
87+
if (!Object.keys(securities).length || !isAuthorized || !security ||
88+
(Array.isArray(operation.security) && !operation.security.length)) {
89+
return request
90+
}
91+
92+
security.forEach((securityObj, index) => {
93+
for (const key in securityObj) {
94+
const auth = authorized[key]
95+
const schema = securityDef[key]
96+
97+
if (!auth) {
98+
continue
99+
}
100+
101+
const value = auth.value || auth
102+
const {type} = schema
103+
104+
if (auth) {
105+
if (type === 'apiKey') {
106+
if (schema.in === 'query') {
107+
result.query[schema.name] = value
108+
}
109+
if (schema.in === 'header') {
110+
result.headers[schema.name] = value
111+
}
112+
if (schema.in === 'cookie') {
113+
result.cookies[schema.name] = value
114+
}
115+
}
116+
else if (type === 'http') {
117+
if (schema.scheme === 'basic') {
118+
const {username, password} = value
119+
const encoded = btoa(`${username}:${password}`)
120+
result.headers.Authorization = `Basic ${encoded}`
121+
}
122+
123+
if (schema.scheme === 'bearer') {
124+
result.headers.Authorization = `Bearer ${value}`
125+
}
126+
}
127+
else if (type === 'oauth2') {
128+
const token = auth.token || {}
129+
const accessToken = token.access_token
130+
let tokenType = token.token_type
131+
132+
if (!tokenType || tokenType.toLowerCase() === 'bearer') {
133+
tokenType = 'Bearer'
134+
}
135+
136+
result.headers.Authorization = `${tokenType} ${accessToken}`
137+
}
138+
}
139+
}
140+
})
141+
142+
return result
143+
}

src/execute/oas3/parameter-builders.js

+11
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,19 @@ function query({req, value, parameter}) {
9191
}
9292
}
9393

94+
const PARAMETER_HEADER_BLACKLIST = [
95+
'accept',
96+
'authorization',
97+
'content-type'
98+
]
99+
94100
function header({req, parameter, value}) {
95101
req.headers = req.headers || {}
102+
103+
if (PARAMETER_HEADER_BLACKLIST.indexOf(parameter.name.toLowerCase()) > -1) {
104+
return
105+
}
106+
96107
if (typeof value !== 'undefined') {
97108
req.headers[parameter.name] = stylize({
98109
key: parameter.name,

src/execute/swagger2/build-request.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import btoa from 'btoa'
55
import assign from 'lodash/assign'
6-
import http, {mergeInQueryOrForm} from '../../http'
6+
import http from '../../http'
77

88

99
export default function (options, req) {

0 commit comments

Comments
 (0)