* create `features` folder * add base oauth2 server * continue implementing OAuth tests * WIP * add password flow tests * modify Password flow credential types * remove query string credential type * add test case for Authorization flow * add specific Authorization value for Password flow test * WIP * fix linter issuesbubble
@@ -2341,28 +2341,49 @@ | |||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"body-parser": { | "body-parser": { | ||||
"version": "1.18.2", | |||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", | |||||
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", | |||||
"version": "1.18.3", | |||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", | |||||
"integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", | |||||
"dev": true, | "dev": true, | ||||
"requires": { | "requires": { | ||||
"bytes": "3.0.0", | "bytes": "3.0.0", | ||||
"content-type": "~1.0.4", | "content-type": "~1.0.4", | ||||
"debug": "2.6.9", | "debug": "2.6.9", | ||||
"depd": "~1.1.1", | |||||
"http-errors": "~1.6.2", | |||||
"iconv-lite": "0.4.19", | |||||
"depd": "~1.1.2", | |||||
"http-errors": "~1.6.3", | |||||
"iconv-lite": "0.4.23", | |||||
"on-finished": "~2.3.0", | "on-finished": "~2.3.0", | ||||
"qs": "6.5.1", | |||||
"raw-body": "2.3.2", | |||||
"type-is": "~1.6.15" | |||||
"qs": "6.5.2", | |||||
"raw-body": "2.3.3", | |||||
"type-is": "~1.6.16" | |||||
}, | }, | ||||
"dependencies": { | "dependencies": { | ||||
"iconv-lite": { | "iconv-lite": { | ||||
"version": "0.4.19", | |||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", | |||||
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", | |||||
"version": "0.4.23", | |||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", | |||||
"integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", | |||||
"dev": true, | |||||
"requires": { | |||||
"safer-buffer": ">= 2.1.2 < 3" | |||||
} | |||||
}, | |||||
"qs": { | |||||
"version": "6.5.2", | |||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", | |||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", | |||||
"dev": true | "dev": true | ||||
}, | |||||
"raw-body": { | |||||
"version": "2.3.3", | |||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", | |||||
"integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", | |||||
"dev": true, | |||||
"requires": { | |||||
"bytes": "3.0.0", | |||||
"http-errors": "1.6.3", | |||||
"iconv-lite": "0.4.23", | |||||
"unpipe": "1.0.0" | |||||
} | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
@@ -6421,14 +6442,14 @@ | |||||
} | } | ||||
}, | }, | ||||
"express": { | "express": { | ||||
"version": "4.16.3", | |||||
"resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", | |||||
"integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", | |||||
"version": "4.16.4", | |||||
"resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", | |||||
"integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", | |||||
"dev": true, | "dev": true, | ||||
"requires": { | "requires": { | ||||
"accepts": "~1.3.5", | "accepts": "~1.3.5", | ||||
"array-flatten": "1.1.1", | "array-flatten": "1.1.1", | ||||
"body-parser": "1.18.2", | |||||
"body-parser": "1.18.3", | |||||
"content-disposition": "0.5.2", | "content-disposition": "0.5.2", | ||||
"content-type": "~1.0.4", | "content-type": "~1.0.4", | ||||
"cookie": "0.3.1", | "cookie": "0.3.1", | ||||
@@ -6445,10 +6466,10 @@ | |||||
"on-finished": "~2.3.0", | "on-finished": "~2.3.0", | ||||
"parseurl": "~1.3.2", | "parseurl": "~1.3.2", | ||||
"path-to-regexp": "0.1.7", | "path-to-regexp": "0.1.7", | ||||
"proxy-addr": "~2.0.3", | |||||
"qs": "6.5.1", | |||||
"proxy-addr": "~2.0.4", | |||||
"qs": "6.5.2", | |||||
"range-parser": "~1.2.0", | "range-parser": "~1.2.0", | ||||
"safe-buffer": "5.1.1", | |||||
"safe-buffer": "5.1.2", | |||||
"send": "0.16.2", | "send": "0.16.2", | ||||
"serve-static": "1.13.2", | "serve-static": "1.13.2", | ||||
"setprototypeof": "1.1.0", | "setprototypeof": "1.1.0", | ||||
@@ -6464,10 +6485,10 @@ | |||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", | ||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"safe-buffer": { | |||||
"version": "5.1.1", | |||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", | |||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", | |||||
"qs": { | |||||
"version": "6.5.2", | |||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", | |||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", | |||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"statuses": { | "statuses": { | ||||
@@ -9397,9 +9418,9 @@ | |||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"ipaddr.js": { | "ipaddr.js": { | ||||
"version": "1.6.0", | |||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", | |||||
"integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=", | |||||
"version": "1.8.0", | |||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", | |||||
"integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", | |||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"is-absolute-url": { | "is-absolute-url": { | ||||
@@ -15478,6 +15499,23 @@ | |||||
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", | ||||
"dev": true | "dev": true | ||||
}, | }, | ||||
"oauth2-server": { | |||||
"version": "2.4.1", | |||||
"resolved": "http://registry.npmjs.org/oauth2-server/-/oauth2-server-2.4.1.tgz", | |||||
"integrity": "sha1-2m3QVMAh7JwpQ59dGijeY9ArcWw=", | |||||
"dev": true, | |||||
"requires": { | |||||
"basic-auth": "~0.0.1" | |||||
}, | |||||
"dependencies": { | |||||
"basic-auth": { | |||||
"version": "0.0.1", | |||||
"resolved": "http://registry.npmjs.org/basic-auth/-/basic-auth-0.0.1.tgz", | |||||
"integrity": "sha1-Md22WEP2w1xv6nvrRqmHy4zhiSQ=", | |||||
"dev": true | |||||
} | |||||
} | |||||
}, | |||||
"object-assign": { | "object-assign": { | ||||
"version": "4.1.1", | "version": "4.1.1", | ||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||
@@ -18364,13 +18402,13 @@ | |||||
} | } | ||||
}, | }, | ||||
"proxy-addr": { | "proxy-addr": { | ||||
"version": "2.0.3", | |||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", | |||||
"integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", | |||||
"version": "2.0.4", | |||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", | |||||
"integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", | |||||
"dev": true, | "dev": true, | ||||
"requires": { | "requires": { | ||||
"forwarded": "~0.1.2", | "forwarded": "~0.1.2", | ||||
"ipaddr.js": "1.6.0" | |||||
"ipaddr.js": "1.8.0" | |||||
} | } | ||||
}, | }, | ||||
"proxy-agent": { | "proxy-agent": { | ||||
@@ -95,9 +95,11 @@ | |||||
"babel-preset-react": "^6.23.0", | "babel-preset-react": "^6.23.0", | ||||
"babel-preset-stage-0": "^6.22.0", | "babel-preset-stage-0": "^6.22.0", | ||||
"babel-runtime": "^6.23.0", | "babel-runtime": "^6.23.0", | ||||
"body-parser": "^1.18.3", | |||||
"bundlesize": "^0.17.0", | "bundlesize": "^0.17.0", | ||||
"chromedriver": "^2.38.3", | "chromedriver": "^2.38.3", | ||||
"copy-webpack-plugin": "^4.0.1", | "copy-webpack-plugin": "^4.0.1", | ||||
"cors": "^2.8.4", | |||||
"css-loader": "^0.28.11", | "css-loader": "^0.28.11", | ||||
"cypress": "^3.1.0", | "cypress": "^3.1.0", | ||||
"dedent": "^0.7.0", | "dedent": "^0.7.0", | ||||
@@ -108,6 +110,7 @@ | |||||
"eslint-plugin-mocha": "^4.11.0", | "eslint-plugin-mocha": "^4.11.0", | ||||
"eslint-plugin-react": "^7.10.0", | "eslint-plugin-react": "^7.10.0", | ||||
"expect": "^1.20.2", | "expect": "^1.20.2", | ||||
"express": "^4.16.4", | |||||
"extract-text-webpack-plugin": "^3.0.2", | "extract-text-webpack-plugin": "^3.0.2", | ||||
"file-loader": "^1.1.11", | "file-loader": "^1.1.11", | ||||
"git-describe": "^4.0.1", | "git-describe": "^4.0.1", | ||||
@@ -124,6 +127,7 @@ | |||||
"npm-run-all": "^4.1.2", | "npm-run-all": "^4.1.2", | ||||
"null-loader": "0.1.1", | "null-loader": "0.1.1", | ||||
"nyc": "^11.3.0", | "nyc": "^11.3.0", | ||||
"oauth2-server": "^2.4.1", | |||||
"open": "0.0.5", | "open": "0.0.5", | ||||
"postcss-loader": "^2.1.5", | "postcss-loader": "^2.1.5", | ||||
"raw-loader": "0.5.1", | "raw-loader": "0.5.1", | ||||
@@ -24,7 +24,7 @@ export default class Oauth2 extends React.Component { | |||||
let username = auth && auth.get("username") || "" | let username = auth && auth.get("username") || "" | ||||
let clientId = auth && auth.get("clientId") || authConfigs.clientId || "" | let clientId = auth && auth.get("clientId") || authConfigs.clientId || "" | ||||
let clientSecret = auth && auth.get("clientSecret") || authConfigs.clientSecret || "" | let clientSecret = auth && auth.get("clientSecret") || authConfigs.clientSecret || "" | ||||
let passwordType = auth && auth.get("passwordType") || "request-body" | |||||
let passwordType = auth && auth.get("passwordType") || "basic" | |||||
this.state = { | this.state = { | ||||
appName: authConfigs.appName, | appName: authConfigs.appName, | ||||
@@ -150,14 +150,13 @@ export default class Oauth2 extends React.Component { | |||||
} | } | ||||
</Row> | </Row> | ||||
<Row> | <Row> | ||||
<label htmlFor="password_type">type:</label> | |||||
<label htmlFor="password_type">Client credentials location:</label> | |||||
{ | { | ||||
isAuthorized ? <code> { this.state.passwordType } </code> | isAuthorized ? <code> { this.state.passwordType } </code> | ||||
: <Col tablet={10} desktop={10}> | : <Col tablet={10} desktop={10}> | ||||
<select id="password_type" data-name="passwordType" onChange={ this.onInputChange }> | <select id="password_type" data-name="passwordType" onChange={ this.onInputChange }> | ||||
<option value="basic">Authorization header</option> | |||||
<option value="request-body">Request body</option> | <option value="request-body">Request body</option> | ||||
<option value="basic">Basic auth</option> | |||||
<option value="query">Query parameters</option> | |||||
</select> | </select> | ||||
</Col> | </Col> | ||||
} | } | ||||
@@ -165,7 +164,7 @@ export default class Oauth2 extends React.Component { | |||||
</Row> | </Row> | ||||
} | } | ||||
{ | { | ||||
( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) && | |||||
( flow === APPLICATION || flow === IMPLICIT || flow === ACCESS_CODE || flow === PASSWORD ) && | |||||
( !isAuthorized || isAuthorized && this.state.clientId) && <Row> | ( !isAuthorized || isAuthorized && this.state.clientId) && <Row> | ||||
<label htmlFor="client_id">client_id:</label> | <label htmlFor="client_id">client_id:</label> | ||||
{ | { | ||||
@@ -183,7 +182,7 @@ export default class Oauth2 extends React.Component { | |||||
} | } | ||||
{ | { | ||||
( flow === APPLICATION || flow === ACCESS_CODE || ( flow === PASSWORD && this.state.passwordType!== "basic") ) && <Row> | |||||
( (flow === APPLICATION || flow === ACCESS_CODE || flow === PASSWORD) && <Row> | |||||
<label htmlFor="client_secret">client_secret:</label> | <label htmlFor="client_secret">client_secret:</label> | ||||
{ | { | ||||
isAuthorized ? <code> ****** </code> | isAuthorized ? <code> ****** </code> | ||||
@@ -197,7 +196,7 @@ export default class Oauth2 extends React.Component { | |||||
} | } | ||||
</Row> | </Row> | ||||
} | |||||
)} | |||||
{ | { | ||||
!isAuthorized && scopes && scopes.size ? <div className="scopes"> | !isAuthorized && scopes && scopes.size ? <div className="scopes"> | ||||
@@ -80,7 +80,7 @@ export default class LiveResponse extends React.Component { | |||||
</div> | </div> | ||||
} | } | ||||
<h4>Server response</h4> | <h4>Server response</h4> | ||||
<table className="responses-table"> | |||||
<table className="responses-table live-responses-table"> | |||||
<thead> | <thead> | ||||
<tr className="responses-header"> | <tr className="responses-header"> | ||||
<td className="col col_header response-col_status">Code</td> | <td className="col col_header response-col_status">Code</td> | ||||
@@ -74,28 +74,23 @@ export const authorizePassword = ( auth ) => ( { authActions } ) => { | |||||
let { schema, name, username, password, passwordType, clientId, clientSecret } = auth | let { schema, name, username, password, passwordType, clientId, clientSecret } = auth | ||||
let form = { | let form = { | ||||
grant_type: "password", | grant_type: "password", | ||||
scope: auth.scopes.join(scopeSeparator) | |||||
scope: auth.scopes.join(scopeSeparator), | |||||
username, | |||||
password | |||||
} | } | ||||
let query = {} | let query = {} | ||||
let headers = {} | let headers = {} | ||||
if ( passwordType === "basic") { | |||||
headers.Authorization = "Basic " + btoa(username + ":" + password) | |||||
} else { | |||||
Object.assign(form, {username}, {password}) | |||||
switch ( passwordType ) { | |||||
case "query": | |||||
setClientIdAndSecret(query, clientId, clientSecret) | |||||
break | |||||
switch (passwordType) { | |||||
case "request-body": | |||||
setClientIdAndSecret(form, clientId, clientSecret) | |||||
break | |||||
case "request-body": | |||||
setClientIdAndSecret(form, clientId, clientSecret) | |||||
break | |||||
default: | |||||
headers.Authorization = "Basic " + btoa(clientId + ":" + clientSecret) | |||||
} | |||||
case "basic": | |||||
headers.Authorization = "Basic " + btoa(clientId + ":" + clientSecret) | |||||
break | |||||
default: | |||||
console.warn(`Warning: invalid passwordType ${passwordType} was passed, not including client id and secret`) | |||||
} | } | ||||
return authActions.authorizeRequest({ body: buildFormData(form), url: schema.get("tokenUrl"), name, headers, query, auth}) | return authActions.authorizeRequest({ body: buildFormData(form), url: schema.get("tokenUrl"), name, headers, query, auth}) | ||||
@@ -0,0 +1,50 @@ | |||||
// from https://github.com/pedroetb/node-oauth2-server-example | |||||
var Http = require("http") | |||||
var path = require("path") | |||||
var express = require("express") | |||||
var bodyParser = require("body-parser") | |||||
var oauthserver = require("oauth2-server") | |||||
var cors = require("cors") | |||||
var app = express() | |||||
app.use(cors()) | |||||
app.use(bodyParser.urlencoded({ extended: true })) | |||||
app.use(bodyParser.json()) | |||||
app.oauth = oauthserver({ | |||||
model: require("./model.js"), | |||||
grants: ["password", "client_credentials", "implicit"], | |||||
debug: true | |||||
}) | |||||
app.all("/oauth/token", app.oauth.grant()) | |||||
app.get("/swagger.yaml", function (req, res) { | |||||
res.sendFile(path.join(__dirname, "swagger.yaml")) | |||||
}) | |||||
app.get("*", app.oauth.authorise(), function (req, res) { | |||||
res.send("Secret secrets are no fun, secret secrets hurt someone.") | |||||
}) | |||||
app.use(app.oauth.errorHandler()) | |||||
function startServer() { | |||||
var httpServer = Http.createServer(app) | |||||
httpServer.listen("3231") | |||||
return function stopServer() { | |||||
httpServer.close() | |||||
} | |||||
} | |||||
module.exports = startServer | |||||
if (require.main === module) { | |||||
// for debugging | |||||
startServer() | |||||
} |
@@ -0,0 +1,141 @@ | |||||
// from https://github.com/pedroetb/node-oauth2-server-example | |||||
var config = { | |||||
clients: [{ | |||||
clientId: "application", | |||||
clientSecret: "secret" | |||||
}], | |||||
confidentialClients: [{ | |||||
clientId: "confidentialApplication", | |||||
clientSecret: "topSecret" | |||||
}], | |||||
tokens: [], | |||||
users: [{ | |||||
id: "123", | |||||
username: "swagger", | |||||
password: "password" | |||||
}] | |||||
} | |||||
/** | |||||
* Dump the memory storage content (for debug). | |||||
*/ | |||||
var dump = function () { | |||||
console.log("clients", config.clients) | |||||
console.log("confidentialClients", config.confidentialClients) | |||||
console.log("tokens", config.tokens) | |||||
console.log("users", config.users) | |||||
} | |||||
/* | |||||
* Methods used by all grant types. | |||||
*/ | |||||
var getAccessToken = function (bearerToken, callback) { | |||||
var tokens = config.tokens.filter(function (token) { | |||||
return token.accessToken === bearerToken | |||||
}) | |||||
return callback(false, tokens[0]) | |||||
} | |||||
var getClient = function (clientId, clientSecret, callback) { | |||||
var clients = config.clients.filter(function (client) { | |||||
return client.clientId === clientId && client.clientSecret === clientSecret | |||||
}) | |||||
var confidentialClients = config.confidentialClients.filter(function (client) { | |||||
return client.clientId === clientId && client.clientSecret === clientSecret | |||||
}) | |||||
callback(false, clients[0] || confidentialClients[0]) | |||||
} | |||||
var grantTypeAllowed = function (clientId, grantType, callback) { | |||||
var clientsSource, | |||||
clients = [] | |||||
if (grantType === "password") { | |||||
clientsSource = config.clients | |||||
} else if (grantType === "client_credentials") { | |||||
clientsSource = config.confidentialClients | |||||
} | |||||
if (clientsSource) { | |||||
clients = clientsSource.filter(function (client) { | |||||
return client.clientId === clientId | |||||
}) | |||||
} | |||||
callback(false, clients.length) | |||||
} | |||||
var saveAccessToken = function (accessToken, clientId, expires, user, callback) { | |||||
config.tokens.push({ | |||||
accessToken: accessToken, | |||||
expires: expires, | |||||
clientId: clientId, | |||||
user: user | |||||
}) | |||||
callback(false) | |||||
} | |||||
/* | |||||
* Method used only by password grant type. | |||||
*/ | |||||
var getUser = function (username, password, callback) { | |||||
var users = config.users.filter(function (user) { | |||||
return user.username === username && user.password === password | |||||
}) | |||||
callback(false, users[0]) | |||||
} | |||||
/* | |||||
* Method used only by client_credentials grant type. | |||||
*/ | |||||
var getUserFromClient = function (clientId, clientSecret, callback) { | |||||
var clients = config.confidentialClients.filter(function (client) { | |||||
return client.clientId === clientId && client.clientSecret === clientSecret | |||||
}) | |||||
var user | |||||
if (clients.length) { | |||||
user = { | |||||
username: clientId | |||||
} | |||||
} | |||||
callback(false, user) | |||||
} | |||||
/** | |||||
* Export model definition object. | |||||
*/ | |||||
module.exports = { | |||||
getAccessToken: getAccessToken, | |||||
getClient: getClient, | |||||
grantTypeAllowed: grantTypeAllowed, | |||||
saveAccessToken: saveAccessToken, | |||||
getUser: getUser, | |||||
getUserFromClient: getUserFromClient | |||||
} |
@@ -0,0 +1,36 @@ | |||||
swagger: "2.0" | |||||
host: localhost:3231 | |||||
paths: | |||||
/password: | |||||
get: | |||||
summary: OAuth2 Password | |||||
security: | |||||
- oauthPassword: [] | |||||
responses: | |||||
200: | |||||
description: OK | |||||
schema: | |||||
type: string | |||||
/application: | |||||
get: | |||||
summary: OAuth2 Application | |||||
security: | |||||
- oauthApplication: [] | |||||
responses: | |||||
200: | |||||
description: OK | |||||
schema: | |||||
type: string | |||||
securityDefinitions: | |||||
oauthPassword: | |||||
type: oauth2 | |||||
flow: password | |||||
tokenUrl: /oauth/token | |||||
oauthApplication: | |||||
type: oauth2 | |||||
flow: application | |||||
tokenUrl: /oauth/token | |||||
oauthImplicit: | |||||
type: oauth2 | |||||
flow: implicit | |||||
authorizationUrl: /oauth/token |
@@ -1,3 +1,4 @@ | |||||
const startOAuthServer = require("../helpers/oauth2-server") | |||||
// *********************************************************** | // *********************************************************** | ||||
// This example plugins/index.js can be used to load plugins | // This example plugins/index.js can be used to load plugins | ||||
// | // | ||||
@@ -12,6 +13,7 @@ | |||||
// the project's config changing) | // the project's config changing) | ||||
module.exports = (on, config) => { | module.exports = (on, config) => { | ||||
startOAuthServer() | |||||
// `on` is used to hook into various events Cypress emits | // `on` is used to hook into various events Cypress emits | ||||
// `config` is the resolved Cypress config | // `config` is the resolved Cypress config | ||||
} | } |
@@ -18,3 +18,10 @@ import "./commands" | |||||
// Alternatively you can use CommonJS syntax: | // Alternatively you can use CommonJS syntax: | ||||
// require('./commands') | // require('./commands') | ||||
// Remove fetch, so Cypress can intercept XHRs | |||||
// see https://github.com/cypress-io/cypress/issues/95 | |||||
Cypress.on("window:before:load", win => { | |||||
win.fetch = null | |||||
}) |
@@ -0,0 +1,55 @@ | |||||
describe("OAuth2 Application flow", function() { | |||||
beforeEach(() => { | |||||
cy.server() | |||||
cy.route({ | |||||
url: "**/oauth/*", | |||||
method: "POST" | |||||
}).as("tokenRequest") | |||||
}) | |||||
it("should make an application flow Authorization header request", () => { | |||||
cy | |||||
.visit("/?url=http://localhost:3231/swagger.yaml") | |||||
.get(".btn.authorize") | |||||
.click() | |||||
.get("div.modal-ux-content > div:nth-child(2)").within(() => { | |||||
cy.get("#client_id") | |||||
.clear() | |||||
.type("confidentialApplication") | |||||
.get("#client_secret") | |||||
.clear() | |||||
.type("topSecret") | |||||
.get("button.btn.modal-btn.auth.authorize.button") | |||||
.click() | |||||
}) | |||||
cy.get("button.close-modal") | |||||
.click() | |||||
.get("#operations-default-get_application") | |||||
.click() | |||||
.get(".btn.try-out__btn") | |||||
.click() | |||||
.get(".btn.execute") | |||||
.click() | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("body") | |||||
.should("equal", "grant_type=client_credentials") | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("headers") | |||||
.its("authorization") | |||||
.should("equal", "Basic Y29uZmlkZW50aWFsQXBwbGljYXRpb246dG9wU2VjcmV0") | |||||
.get(".live-responses-table .response-col_status") | |||||
.contains("200") | |||||
}) | |||||
}) |
@@ -0,0 +1,122 @@ | |||||
describe("OAuth2 Password flow", function() { | |||||
beforeEach(() => { | |||||
cy.server() | |||||
cy.route({ | |||||
url: "**/oauth/*", | |||||
method: "POST" | |||||
}).as("tokenRequest") | |||||
}) | |||||
it("should make a password flow Authorization header request", () => { | |||||
cy | |||||
.visit("/?url=http://localhost:3231/swagger.yaml") | |||||
.get(".btn.authorize") | |||||
.click() | |||||
.get("#oauth_username") | |||||
.type("swagger") | |||||
.get("#oauth_password") | |||||
.type("password") | |||||
.get("#password_type") | |||||
.select("basic") | |||||
.get("#client_id") | |||||
.clear() | |||||
.type("application") | |||||
.get("#client_secret") | |||||
.clear() | |||||
.type("secret") | |||||
.get("div.modal-ux-content > div:nth-child(1) > div > div:nth-child(2) > div > div.auth-btn-wrapper > button.btn.modal-btn.auth.authorize.button") | |||||
.click() | |||||
.get("button.close-modal") | |||||
.click() | |||||
.get("#operations-default-get_password") | |||||
.click() | |||||
.get(".btn.try-out__btn") | |||||
.click() | |||||
.get(".btn.execute") | |||||
.click() | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("body") | |||||
.should("include", "grant_type=password") | |||||
.should("include", "username=swagger") | |||||
.should("include", "password=password") | |||||
.should("not.include", "client_id") | |||||
.should("not.include", "client_secret") | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("headers") | |||||
.its("authorization") | |||||
.should("equal", "Basic YXBwbGljYXRpb246c2VjcmV0") | |||||
.get(".live-responses-table .response-col_status") | |||||
.contains("200") | |||||
}) | |||||
it("should make a Password flow request-body request", () => { | |||||
cy | |||||
.visit("/?url=http://localhost:3231/swagger.yaml") | |||||
.get(".btn.authorize") | |||||
.click() | |||||
.get("#oauth_username") | |||||
.type("swagger") | |||||
.get("#oauth_password") | |||||
.type("password") | |||||
.get("#password_type") | |||||
.select("request-body") | |||||
.get("#client_id") | |||||
.clear() | |||||
.type("application") | |||||
.get("#client_secret") | |||||
.clear() | |||||
.type("secret") | |||||
.get("div.modal-ux-content > div:nth-child(1) > div > div:nth-child(2) > div > div.auth-btn-wrapper > button.btn.modal-btn.auth.authorize.button") | |||||
.click() | |||||
.get("button.close-modal") | |||||
.click() | |||||
.get("#operations-default-get_password") | |||||
.click() | |||||
.get(".btn.try-out__btn") | |||||
.click() | |||||
.get(".btn.execute") | |||||
.click() | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("body") | |||||
.should("include", "grant_type=password") | |||||
.should("include", "username=swagger") | |||||
.should("include", "password=password") | |||||
.should("include", "client_id=application") | |||||
.should("include", "client_secret=secret") | |||||
cy.get("@tokenRequest") | |||||
.its("request") | |||||
.its("headers") | |||||
.should("not.have.property", "authorization") | |||||
.get(".live-responses-table .response-col_status") | |||||
.contains("200") | |||||
}) | |||||
}) |