diff --git a/.eslintrc b/.eslintrc index 3ef5eda..8e36b31 100644 --- a/.eslintrc +++ b/.eslintrc @@ -34,6 +34,13 @@ "no-console": [ "error" ], + "no-var": [ + "error" + ], + "prefer-const": ["error", { + "destructuring": "any", + "ignoreReadBeforeAssign": false + }], "no-unused-vars": [ "error", { diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1523759 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,52 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages + +name: Release + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 12 + - run: npm ci + - run: npm test + + publish-npm: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + # we always publish targeting the lowest supported node version + node-version: 12 + registry-url: 'https://registry.npmjs.org/' + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} + + publish-gpr: + needs: build + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + # we always publish targeting the lowest supported node version + node-version: 12 + registry-url: $registry-url(npm) + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/tests-release.yml b/.github/workflows/tests-release.yml new file mode 100644 index 0000000..7a6dce7 --- /dev/null +++ b/.github/workflows/tests-release.yml @@ -0,0 +1,155 @@ +name: Tests for Release + +on: + push: + branches: + - release-* # all release- branches + pull_request: + types: [review_requested, ready_for_review] # only non-draft PR + branches: + - release-* # all release- branches + + +jobs: + # STEP 1 - NPM Audit + + # Before we even test a thing we want to have a clean audit! Since this is + # sufficient to be done using the lowest node version, we can easily use + # a fixed one: + + audit: + name: NPM Audit + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup node 12 + uses: actions/setup-node@v1 + with: + node-version: 12 + - run: npm audit --production # no audit for dev dependencies + + # STEP 2 - basic unit tests + + # This is the standard unit tests as we do in the basic tests for every PR + unittest: + name: Basic unit tests + runs-on: ubuntu-latest + needs: [audit] + strategy: + matrix: + node: [12, 14, 16] + steps: + - name: Checkout ${{ matrix.node }} + uses: actions/checkout@v2 + + - name: Setup node ${{ matrix.node }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - name: Cache dependencies ${{ matrix.node }} + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node }} + + # for this workflow we also require npm audit to pass + - run: npm ci + - run: npm run test:coverage + + # with the following action we enforce PRs to have a high coverage + # and ensure, changes are tested well enough so that coverage won't fail + - name: check coverage + uses: devmasx/coverage-check-action@v1.2.0 + with: + type: lcov + result_path: coverage/lcov.info + min_coverage: 95 + token: ${{github.token}} + + # STEP 3 - Integration tests + + # Since our release may affect several packages that depend on it we need to + # cover the closest ones, like adapters and examples. + + integrationtests: + name: Extended integration tests + runs-on: ubuntu-latest + needs: [unittest] + strategy: + matrix: + node: [12, 14, 16] + steps: + # checkout this repo + - name: Checkout ${{ matrix.node }} + uses: actions/checkout@v2 + + # checkout express-adapter repo + - name: Checkout express-adapter ${{ matrix.node }} + uses: actions/checkout@v2 + with: + repository: node-oauth/express-adapter + path: github/testing + + # place checkout for other adapters here + - name: Setup node ${{ matrix.node }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node }} + + - name: Cache dependencies ${{ matrix.node }} + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node }} + + # in order to test the adapter we need to use the current state + # we just cloned and install it as local dependency + - run: cd github/testing/express-adapter && npm ci + - run: cd github/testing/express-adapter && npm install ./ + - run: cd github/testing/express-adapter && npm run tests + + # todo repeat with other adapters + + npmpubdry: + name: NPM Publish Dry-run + runs-on: ubuntu-latest + needs: [integrationtests] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup node 12 + uses: actions/setup-node@v1 + with: + node-version: '12.x' + registry-url: 'https://registry.npmjs.org' + - run: npm install + - run: npm publish --dry-run + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + ghpubdry: + needs: [integrationtests] + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + # we always publish targeting the lowest supported node version + node-version: 12 + registry-url: $registry-url(npm) + - run: npm ci + - run: npm publish --dry-run + env: + NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 26c6ed7..a74688f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,44 +1,21 @@ -name: Test suite +name: Tests + +# This workflow runs standard unit tests to ensure basic integrity and avoid +# regressions on pull-requests (and pushes) on: push: branches: - - master # allthough master is push protected we still keep it + - master # allthough master is push protected we still keep it - development - pull_request: # runs on all PR + pull_request: # runs on all PR + branches-ignore: + - release-* # on release we run an extended workflow so no need for this jobs: - # ---------------------------------- - # uncomment when a linter is added - # ---------------------------------- - - # lintjs: - # name: Javascript lint - # runs-on: ubuntu-latest - # steps: - # - name: checkout - # uses: actions/checkout@v2 - # - # - name: setup node - # uses: actions/setup-node@v1 - # with: - # node-version: '12.x' - # - # - name: cache dependencies - # uses: actions/cache@v1 - # with: - # path: ~/.npm - # key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - # restore-keys: | - # ${{ runner.os }}-node- - # - run: npm ci - # - run: npm run lint - unittest: name: unit tests runs-on: ubuntu-latest - # uncomment when a linter is added - # needs: [lintjs] strategy: matrix: node: [12, 14, 16] @@ -61,15 +38,12 @@ jobs: - run: npm ci - run: npm run test:coverage - # ---------------------------------- - # uncomment when a linter is added - # ---------------------------------- - - # - name: check coverage - # uses: devmasx/coverage-check-action@v1.2.0 - # with: - # type: lcov - # result_path: coverage/lcov.info - # min_coverage: 90 - # token: ${{github.token}} - + # with the following action we enforce PRs to have a high coverage + # and ensure, changes are tested well enough so that coverage won't fail + - name: check coverage + uses: devmasx/coverage-check-action@v1.2.0 + with: + type: lcov + result_path: coverage/lcov.info + min_coverage: 95 + token: ${{github.token}} diff --git a/CHANGELOG.md b/CHANGELOG.md index d2be068..e258b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ ## Changelog +## 4.1.1 + +### Added +- Added TypeScript types +### Changed +- Removed extra files when someone npm installs. +- Upgrades all code from ES5 to ES6, where possible. + +## 4.1.0 +### Changed +* Bump dev dependencies to resolve vulnerabilities +* Replaced jshint with eslint along with should and chai +* Use sha256 when generating tokens + +### Added +* Added markdown files to discuss coding rules, commit conventions, contributing guidelines, etc. + +### Removed +* Removed lodash dependency +* Removed statuses package and use built in http.STATUS_CODES instead. + ### 4.0.0 * Bump jshint from 2.12.0 to 2.13.0 * Bump jshint from 2.12.0 to 2.13.0 diff --git a/docs/model/overview.rst b/docs/model/overview.rst index 5e345ab..62c9ffa 100644 --- a/docs/model/overview.rst +++ b/docs/model/overview.rst @@ -37,6 +37,7 @@ Model functions used by the authorization code grant: - :ref:`Model#saveAuthorizationCode` - :ref:`Model#revokeAuthorizationCode` - :ref:`Model#validateScope` +- :ref:`Model#validateRedirectUri` -------- diff --git a/docs/model/spec.rst b/docs/model/spec.rst index 4cdd1fd..953c281 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -214,7 +214,7 @@ An ``Object`` representing the access token and associated data. function getAccessToken(accessToken) { // imaginary DB queries - db.queryAccessToken({access_token: accessToken}) + return db.queryAccessToken({access_token: accessToken}) .then(function(token) { return Promise.all([ token, @@ -288,7 +288,7 @@ An ``Object`` representing the refresh token and associated data. function getRefreshToken(refreshToken) { // imaginary DB queries - db.queryRefreshToken({refresh_token: refreshToken}) + return db.queryRefreshToken({refresh_token: refreshToken}) .then(function(token) { return Promise.all([ token, @@ -364,7 +364,7 @@ An ``Object`` representing the authorization code and associated data. function getAuthorizationCode(authorizationCode) { // imaginary DB queries - db.queryAuthorizationCode({authorization_code: authorizationCode}) + return db.queryAuthorizationCode({authorization_code: authorizationCode}) .then(function(code) { return Promise.all([ code, @@ -446,7 +446,7 @@ The return value (``client``) can carry additional properties that will be ignor if (clientSecret) { params.client_secret = clientSecret; } - db.queryClient(params) + return db.queryClient(params) .then(function(client) { return { id: client.id, @@ -985,3 +985,44 @@ Returns ``true`` if the access token passes, ``false`` otherwise. return requestedScopes.every(s => authorizedScopes.indexOf(s) >= 0); } +-------- + +.. _Model#validateRedirectUri: + +``validateRedirectUri(redirectUri, client, [callback])`` +================================================================ + +Invoked to check if the provided ``redirectUri`` is valid for a particular ``client``. + +This model function is **optional**. If not implemented, the ``redirectUri`` should be included in the provided ``redirectUris`` of the client. + +**Invoked during:** + +- ``authorization_code`` grant + +**Arguments:** + ++-----------------+----------+---------------------------------------------------------------------+ +| Name | Type | Description | ++=================+==========+=====================================================================+ +| redirect_uri | String | The redirect URI to validate. | ++-----------------+----------+---------------------------------------------------------------------+ +| client | Object | The associated client. | ++-----------------+----------+---------------------------------------------------------------------+ + +**Return value:** + +Returns ``true`` if the ``redirectUri`` is valid, ``false`` otherwise. + +**Remarks:** +When implementing this method you should take care of possible security risks related to ``redirectUri``. +.. _rfc6819: https://datatracker.ietf.org/doc/html/rfc6819 + +Section-5.2.3.5 is implemented by default. +.. _Section-5.2.3.5: https://datatracker.ietf.org/doc/html/rfc6819#section-5.2.3.5 + +:: + + function validateRedirectUri(redirectUri, client) { + return client.redirectUris.includes(redirectUri); + } diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..260e34a --- /dev/null +++ b/index.d.ts @@ -0,0 +1,476 @@ +// Type definitions for Node OAuth2 Server 4.0 +// Definitions by: Robbie Van Gorkom , +// Charles Irick , +// Daniel Fischer , +// Vitor Santos + +import * as http from 'http'; + +/** + * Represents an OAuth2 server instance. + */ +declare class OAuth2Server { + static OAuth2Server: typeof OAuth2Server; + + /** + * Instantiates OAuth2Server using the supplied model + */ + constructor(options: OAuth2Server.ServerOptions); + + /** + * Authenticates a request. + */ + authenticate( + request: OAuth2Server.Request, + response: OAuth2Server.Response, + options?: OAuth2Server.AuthenticateOptions, + callback?: OAuth2Server.Callback + ): Promise; + + /** + * Authorizes a token request. + */ + authorize( + request: OAuth2Server.Request, + response: OAuth2Server.Response, + options?: OAuth2Server.AuthorizeOptions, + callback?: OAuth2Server.Callback + ): Promise; + + /** + * Retrieves a new token for an authorized token request. + */ + token( + request: OAuth2Server.Request, + response: OAuth2Server.Response, + options?: OAuth2Server.TokenOptions, + callback?: OAuth2Server.Callback + ): Promise; +} + +declare namespace OAuth2Server { + /** + * Represents an incoming HTTP request. + */ + class Request { + body?: any; + headers?: { [key: string]: string; } | undefined; + method?: string | undefined; + query?: { [key: string]: string; } | undefined; + + /** + * Instantiates Request using the supplied options. + * + */ + constructor(options?: { [key: string]: any } | http.IncomingMessage); + + /** + * Returns the specified HTTP header field. The match is case-insensitive. + * + */ + get(field: string): any | undefined; + + /** + * Checks if the request’s Content-Type HTTP header matches any of the given MIME types. + * + */ + is(types: string[]): string | false; + } + + /** + * Represents an outgoing HTTP response. + */ + class Response { + body?: any; + headers?: { [key: string]: string; } | undefined; + status?: number | undefined; + + /** + * Instantiates Response using the supplied options. + * + */ + constructor(options?: { [key: string]: any; } | http.ServerResponse); + + /** + * Returns the specified HTTP header field. The match is case-insensitive. + * + */ + get(field: string): any | undefined; + + /** + * Sets the specified HTTP header field. The match is case-insensitive. + * + */ + set(field: string, value: string): void; + + /** + * Redirects to the specified URL using 302 Found. + * + */ + redirect(url: string): void; + } + + abstract class AbstractGrantType { + /** + * Instantiates AbstractGrantType using the supplied options. + * + */ + constructor(options: TokenOptions) + + /** + * Generate access token. Calls Model#generateAccessToken() if implemented. + * + */ + generateAccessToken(client: Client, user: User, scope: string | string[]): Promise; + + /** + * Generate refresh token. Calls Model#generateRefreshToken() if implemented. + * + */ + generateRefreshToken(client: Client, user: User, scope: string | string[]): Promise; + + /** + * Get access token expiration date. + * + */ + getAccessTokenExpiresAt(): Date; + + /** + * Get refresh token expiration date. + * + */ + getRefreshTokenExpiresAt(): Date; + + /** + * Get scope from the request body. + * + */ + getScope(request: Request): string; + + /** + * Validate requested scope. Calls Model#validateScope() if implemented. + * + */ + validateScope(user: User, client: Client, scope: string | string[]): Promise; + + /** + * Retrieve info from the request and client and return token + * + */ + abstract handle(request: Request, client: Client): Promise; + } + + interface ServerOptions extends AuthenticateOptions, AuthorizeOptions, TokenOptions { + /** + * Model object + */ + model: AuthorizationCodeModel | ClientCredentialsModel | RefreshTokenModel | PasswordModel | ExtensionModel; + } + + interface AuthenticateOptions { + /** + * The scope(s) to authenticate. + */ + scope?: string | string[] | undefined; + + /** + * Set the X-Accepted-OAuth-Scopes HTTP header on response objects. + */ + addAcceptedScopesHeader?: boolean | undefined; + + /** + * Set the X-OAuth-Scopes HTTP header on response objects. + */ + addAuthorizedScopesHeader?: boolean | undefined; + + /** + * Allow clients to pass bearer tokens in the query string of a request. + */ + allowBearerTokensInQueryString?: boolean | undefined; + } + + interface AuthorizeOptions { + /** + * The authenticate handler + */ + authenticateHandler?: {} | undefined; + + /** + * Allow clients to specify an empty state + */ + allowEmptyState?: boolean | undefined; + + /** + * Lifetime of generated authorization codes in seconds (default = 5 minutes). + */ + authorizationCodeLifetime?: number | undefined; + } + + interface TokenOptions { + /** + * Lifetime of generated access tokens in seconds (default = 1 hour) + */ + accessTokenLifetime?: number | undefined; + + /** + * Lifetime of generated refresh tokens in seconds (default = 2 weeks) + */ + refreshTokenLifetime?: number | undefined; + + /** + * Allow extended attributes to be set on the returned token + */ + allowExtendedTokenAttributes?: boolean | undefined; + + /** + * Require a client secret. Defaults to true for all grant types. + */ + requireClientAuthentication?: {} | undefined; + + /** + * Always revoke the used refresh token and issue a new one for the refresh_token grant. + */ + alwaysIssueNewRefreshToken?: boolean | undefined; + + /** + * Additional supported grant types. + */ + extendedGrantTypes?: { [key: string]: typeof AbstractGrantType } | undefined; + } + + /** + * Represents a generic callback structure for model callbacks + */ + type Callback = (err?: any, result?: T) => void; + + /** + * For returning falsey parameters in cases of failure + */ + type Falsey = '' | 0 | false | null | undefined; + + interface BaseModel { + /** + * Invoked to generate a new access token. + * + */ + generateAccessToken?(client: Client, user: User, scope: string | string[], callback?: Callback): Promise; + + /** + * Invoked to retrieve a client using a client id or a client id/client secret combination, depending on the grant type. + * + */ + getClient(clientId: string, clientSecret: string, callback?: Callback): Promise; + + /** + * Invoked to save an access token and optionally a refresh token, depending on the grant type. + * + */ + saveToken(token: Token, client: Client, user: User, callback?: Callback): Promise; + } + + interface RequestAuthenticationModel { + /** + * Invoked to retrieve an existing access token previously saved through Model#saveToken(). + * + */ + getAccessToken(accessToken: string, callback?: Callback): Promise; + + /** + * Invoked during request authentication to check if the provided access token was authorized the requested scopes. + * + */ + verifyScope(token: Token, scope: string | string[], callback?: Callback): Promise; + } + + interface AuthorizationCodeModel extends BaseModel, RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?(client: Client, user: User, scope: string | string[], callback?: Callback): Promise; + + /** + * Invoked to generate a new authorization code. + * + */ + generateAuthorizationCode?(client: Client, user: User, scope: string | string[], callback?: Callback): Promise; + + /** + * Invoked to retrieve an existing authorization code previously saved through Model#saveAuthorizationCode(). + * + */ + getAuthorizationCode(authorizationCode: string, callback?: Callback): Promise; + + /** + * Invoked to save an authorization code. + * + */ + saveAuthorizationCode( + code: Pick, + client: Client, + user: User, + callback?: Callback): Promise; + + /** + * Invoked to revoke an authorization code. + * + */ + revokeAuthorizationCode(code: AuthorizationCode, callback?: Callback): Promise; + + /** + * Invoked to check if the requested scope is valid for a particular client/user combination. + * + */ + validateScope?(user: User, client: Client, scope: string | string[], callback?: Callback): Promise; + } + + interface PasswordModel extends BaseModel, RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?(client: Client, user: User, scope: string | string[], callback?: Callback): Promise; + + /** + * Invoked to retrieve a user using a username/password combination. + * + */ + getUser(username: string, password: string, callback?: Callback): Promise; + + /** + * Invoked to check if the requested scope is valid for a particular client/user combination. + * + */ + validateScope?(user: User, client: Client, scope: string | string[], callback?: Callback): Promise; + } + + interface RefreshTokenModel extends BaseModel, RequestAuthenticationModel { + /** + * Invoked to generate a new refresh token. + * + */ + generateRefreshToken?(client: Client, user: User, scope: string | string[], callback?: Callback): Promise; + + /** + * Invoked to retrieve an existing refresh token previously saved through Model#saveToken(). + * + */ + getRefreshToken(refreshToken: string, callback?: Callback): Promise; + + /** + * Invoked to revoke a refresh token. + * + */ + revokeToken(token: RefreshToken | Token, callback?: Callback): Promise; + } + + interface ClientCredentialsModel extends BaseModel, RequestAuthenticationModel { + /** + * Invoked to retrieve the user associated with the specified client. + * + */ + getUserFromClient(client: Client, callback?: Callback): Promise; + + /** + * Invoked to check if the requested scope is valid for a particular client/user combination. + * + */ + validateScope?(user: User, client: Client, scope: string | string[], callback?: Callback): Promise; + } + + interface ExtensionModel extends BaseModel, RequestAuthenticationModel {} + + /** + * An interface representing the user. + * A user object is completely transparent to oauth2-server and is simply used as input to model functions. + */ + interface User { + [key: string]: any; + } + + /** + * An interface representing the client and associated data + */ + interface Client { + id: string; + redirectUris?: string | string[] | undefined; + grants: string | string[]; + accessTokenLifetime?: number | undefined; + refreshTokenLifetime?: number | undefined; + [key: string]: any; + } + + /** + * An interface representing the authorization code and associated data. + */ + interface AuthorizationCode { + authorizationCode: string; + expiresAt: Date; + redirectUri: string; + scope?: string | string[] | undefined; + client: Client; + user: User; + [key: string]: any; + } + + /** + * An interface representing the token(s) and associated data. + */ + interface Token { + accessToken: string; + accessTokenExpiresAt?: Date | undefined; + refreshToken?: string | undefined; + refreshTokenExpiresAt?: Date | undefined; + scope?: string | string[] | undefined; + client: Client; + user: User; + [key: string]: any; + } + + /** + * An interface representing the refresh token and associated data. + */ + interface RefreshToken { + refreshToken: string; + refreshTokenExpiresAt?: Date | undefined; + scope?: string | string[] | undefined; + client: Client; + user: User; + [key: string]: any; + } + + class OAuthError extends Error { + constructor(messageOrError: string | Error, properties?: object); + + /** + * The HTTP error code. + */ + code: number; + + /** + * The OAuth error code. + */ + name: string; + + /** + * A human-readable error message. + */ + message: string; + } + + class AccessDeniedError extends OAuthError {} + class InsufficientScopeError extends OAuthError {} + class InvalidArgumentError extends OAuthError {} + class InvalidClientError extends OAuthError {} + class InvalidGrantError extends OAuthError {} + class InvalidRequestError extends OAuthError {} + class InvalidScopeError extends OAuthError {} + class InvalidTokenError extends OAuthError {} + class ServerError extends OAuthError {} + class UnauthorizedClientError extends OAuthError {} + class UnauthorizedRequestError extends OAuthError {} + class UnsupportedGrantTypeError extends OAuthError {} + class UnsupportedResponseTypeError extends OAuthError {} +} + +export = OAuth2Server; diff --git a/lib/errors/access-denied-error.js b/lib/errors/access-denied-error.js index 0f3dc2f..ce5c0af 100644 --- a/lib/errors/access-denied-error.js +++ b/lib/errors/access-denied-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/insufficient-scope-error.js b/lib/errors/insufficient-scope-error.js index c522df7..a27ad68 100644 --- a/lib/errors/insufficient-scope-error.js +++ b/lib/errors/insufficient-scope-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-argument-error.js b/lib/errors/invalid-argument-error.js index b667468..1958caa 100644 --- a/lib/errors/invalid-argument-error.js +++ b/lib/errors/invalid-argument-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-client-error.js b/lib/errors/invalid-client-error.js index 31aea2d..1513d57 100644 --- a/lib/errors/invalid-client-error.js +++ b/lib/errors/invalid-client-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-grant-error.js b/lib/errors/invalid-grant-error.js index 810242d..2c6a568 100644 --- a/lib/errors/invalid-grant-error.js +++ b/lib/errors/invalid-grant-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-request-error.js b/lib/errors/invalid-request-error.js index bfb178a..56e997e 100644 --- a/lib/errors/invalid-request-error.js +++ b/lib/errors/invalid-request-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-scope-error.js b/lib/errors/invalid-scope-error.js index bcded24..2f5746d 100644 --- a/lib/errors/invalid-scope-error.js +++ b/lib/errors/invalid-scope-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/invalid-token-error.js b/lib/errors/invalid-token-error.js index cb12c3e..e79d926 100644 --- a/lib/errors/invalid-token-error.js +++ b/lib/errors/invalid-token-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/oauth-error.js b/lib/errors/oauth-error.js index fc66f75..a96a41f 100644 --- a/lib/errors/oauth-error.js +++ b/lib/errors/oauth-error.js @@ -3,15 +3,15 @@ /** * Module dependencies. */ -var util = require('util'); -var http = require('http'); +const util = require('util'); +const http = require('http'); /** * Constructor. */ function OAuthError(messageOrError, properties) { - var message = messageOrError instanceof Error ? messageOrError.message : messageOrError; - var error = messageOrError instanceof Error ? messageOrError : null; + let message = messageOrError instanceof Error ? messageOrError.message : messageOrError; + const error = messageOrError instanceof Error ? messageOrError : null; if (properties == null || !Object.entries(properties).length ) { properties = {}; } @@ -26,7 +26,7 @@ function OAuthError(messageOrError, properties) { } this.code = this.status = this.statusCode = properties.code; this.message = message; - for (var key in properties) { + for (const key in properties) { if (key !== 'code') { this[key] = properties[key]; } diff --git a/lib/errors/server-error.js b/lib/errors/server-error.js index a1bdcf9..aee958b 100644 --- a/lib/errors/server-error.js +++ b/lib/errors/server-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/unauthorized-client-error.js b/lib/errors/unauthorized-client-error.js index eca0d68..fde3cb5 100644 --- a/lib/errors/unauthorized-client-error.js +++ b/lib/errors/unauthorized-client-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/unauthorized-request-error.js b/lib/errors/unauthorized-request-error.js index afb11b8..e960489 100644 --- a/lib/errors/unauthorized-request-error.js +++ b/lib/errors/unauthorized-request-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/unsupported-grant-type-error.js b/lib/errors/unsupported-grant-type-error.js index 63345ce..586a743 100644 --- a/lib/errors/unsupported-grant-type-error.js +++ b/lib/errors/unsupported-grant-type-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/errors/unsupported-response-type-error.js b/lib/errors/unsupported-response-type-error.js index 861ac34..539551e 100644 --- a/lib/errors/unsupported-response-type-error.js +++ b/lib/errors/unsupported-response-type-error.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var OAuthError = require('./oauth-error'); -var util = require('util'); +const OAuthError = require('./oauth-error'); +const util = require('util'); /** * Constructor. diff --git a/lib/grant-types/abstract-grant-type.js b/lib/grant-types/abstract-grant-type.js index 224a473..d9894b6 100644 --- a/lib/grant-types/abstract-grant-type.js +++ b/lib/grant-types/abstract-grant-type.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidScopeError = require('../errors/invalid-scope-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var is = require('../validator/is'); -var tokenUtil = require('../utils/token-util'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidScopeError = require('../errors/invalid-scope-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const isFormat = require('@node-oauth/formats'); +const tokenUtil = require('../utils/token-util'); /** * Constructor. @@ -83,7 +83,7 @@ AbstractGrantType.prototype.getRefreshTokenExpiresAt = function() { */ AbstractGrantType.prototype.getScope = function(request) { - if (!is.nqschar(request.body.scope)) { + if (!isFormat.nqschar(request.body.scope)) { throw new InvalidArgumentError('Invalid parameter: `scope`'); } diff --git a/lib/grant-types/authorization-code-grant-type.js b/lib/grant-types/authorization-code-grant-type.js index 97c1267..ed66eea 100644 --- a/lib/grant-types/authorization-code-grant-type.js +++ b/lib/grant-types/authorization-code-grant-type.js @@ -4,15 +4,15 @@ * Module dependencies. */ -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var ServerError = require('../errors/server-error'); -var is = require('../validator/is'); -var util = require('util'); +const AbstractGrantType = require('./abstract-grant-type'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidGrantError = require('../errors/invalid-grant-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const ServerError = require('../errors/server-error'); +const isFormat = require('@node-oauth/formats'); +const util = require('util'); /** * Constructor. @@ -85,7 +85,7 @@ AuthorizationCodeGrantType.prototype.getAuthorizationCode = function(request, cl throw new InvalidRequestError('Missing parameter: `code`'); } - if (!is.vschar(request.body.code)) { + if (!isFormat.vschar(request.body.code)) { throw new InvalidRequestError('Invalid parameter: `code`'); } return promisify(this.model.getAuthorizationCode, 1).call(this.model, request.body.code) @@ -114,7 +114,7 @@ AuthorizationCodeGrantType.prototype.getAuthorizationCode = function(request, cl throw new InvalidGrantError('Invalid grant: authorization code has expired'); } - if (code.redirectUri && !is.uri(code.redirectUri)) { + if (code.redirectUri && !isFormat.uri(code.redirectUri)) { throw new InvalidGrantError('Invalid grant: `redirect_uri` is not a valid URI'); } @@ -138,9 +138,9 @@ AuthorizationCodeGrantType.prototype.validateRedirectUri = function(request, cod return; } - var redirectUri = request.body.redirect_uri || request.query.redirect_uri; + const redirectUri = request.body.redirect_uri || request.query.redirect_uri; - if (!is.uri(redirectUri)) { + if (!isFormat.uri(redirectUri)) { throw new InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); } @@ -175,7 +175,7 @@ AuthorizationCodeGrantType.prototype.revokeAuthorizationCode = function(code) { */ AuthorizationCodeGrantType.prototype.saveToken = function(user, client, authorizationCode, scope) { - var fns = [ + const fns = [ this.validateScope(user, client, scope), this.generateAccessToken(client, user, scope), this.generateRefreshToken(client, user, scope), @@ -186,7 +186,7 @@ AuthorizationCodeGrantType.prototype.saveToken = function(user, client, authoriz return Promise.all(fns) .bind(this) .spread(function(scope, accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { + const token = { accessToken: accessToken, authorizationCode: authorizationCode, accessTokenExpiresAt: accessTokenExpiresAt, diff --git a/lib/grant-types/client-credentials-grant-type.js b/lib/grant-types/client-credentials-grant-type.js index 138333e..d0af0fe 100644 --- a/lib/grant-types/client-credentials-grant-type.js +++ b/lib/grant-types/client-credentials-grant-type.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var util = require('util'); +const AbstractGrantType = require('./abstract-grant-type'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidGrantError = require('../errors/invalid-grant-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const util = require('util'); /** * Constructor. @@ -54,7 +54,7 @@ ClientCredentialsGrantType.prototype.handle = function(request, client) { throw new InvalidArgumentError('Missing parameter: `client`'); } - var scope = this.getScope(request); + const scope = this.getScope(request); return Promise.bind(this) .then(function() { @@ -85,7 +85,7 @@ ClientCredentialsGrantType.prototype.getUserFromClient = function(client) { */ ClientCredentialsGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ + const fns = [ this.validateScope(user, client, scope), this.generateAccessToken(client, user, scope), this.getAccessTokenExpiresAt(client, user, scope) @@ -94,7 +94,7 @@ ClientCredentialsGrantType.prototype.saveToken = function(user, client, scope) { return Promise.all(fns) .bind(this) .spread(function(scope, accessToken, accessTokenExpiresAt) { - var token = { + const token = { accessToken: accessToken, accessTokenExpiresAt: accessTokenExpiresAt, scope: scope diff --git a/lib/grant-types/password-grant-type.js b/lib/grant-types/password-grant-type.js index b7f1793..b65f9e1 100644 --- a/lib/grant-types/password-grant-type.js +++ b/lib/grant-types/password-grant-type.js @@ -4,14 +4,14 @@ * Module dependencies. */ -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var is = require('../validator/is'); -var util = require('util'); +const AbstractGrantType = require('./abstract-grant-type'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidGrantError = require('../errors/invalid-grant-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const isFormat = require('@node-oauth/formats'); +const util = require('util'); /** * Constructor. @@ -56,7 +56,7 @@ PasswordGrantType.prototype.handle = function(request, client) { throw new InvalidArgumentError('Missing parameter: `client`'); } - var scope = this.getScope(request); + const scope = this.getScope(request); return Promise.bind(this) .then(function() { @@ -80,11 +80,11 @@ PasswordGrantType.prototype.getUser = function(request) { throw new InvalidRequestError('Missing parameter: `password`'); } - if (!is.uchar(request.body.username)) { + if (!isFormat.uchar(request.body.username)) { throw new InvalidRequestError('Invalid parameter: `username`'); } - if (!is.uchar(request.body.password)) { + if (!isFormat.uchar(request.body.password)) { throw new InvalidRequestError('Invalid parameter: `password`'); } @@ -103,7 +103,7 @@ PasswordGrantType.prototype.getUser = function(request) { */ PasswordGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ + const fns = [ this.validateScope(user, client, scope), this.generateAccessToken(client, user, scope), this.generateRefreshToken(client, user, scope), @@ -114,7 +114,7 @@ PasswordGrantType.prototype.saveToken = function(user, client, scope) { return Promise.all(fns) .bind(this) .spread(function(scope, accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { + const token = { accessToken: accessToken, accessTokenExpiresAt: accessTokenExpiresAt, refreshToken: refreshToken, diff --git a/lib/grant-types/refresh-token-grant-type.js b/lib/grant-types/refresh-token-grant-type.js index 19f9010..c9a25df 100644 --- a/lib/grant-types/refresh-token-grant-type.js +++ b/lib/grant-types/refresh-token-grant-type.js @@ -4,15 +4,15 @@ * Module dependencies. */ -var AbstractGrantType = require('./abstract-grant-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidGrantError = require('../errors/invalid-grant-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var ServerError = require('../errors/server-error'); -var is = require('../validator/is'); -var util = require('util'); +const AbstractGrantType = require('./abstract-grant-type'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidGrantError = require('../errors/invalid-grant-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const ServerError = require('../errors/server-error'); +const isFormat = require('@node-oauth/formats'); +const util = require('util'); /** * Constructor. @@ -82,7 +82,7 @@ RefreshTokenGrantType.prototype.getRefreshToken = function(request, client) { throw new InvalidRequestError('Missing parameter: `refresh_token`'); } - if (!is.vschar(request.body.refresh_token)) { + if (!isFormat.vschar(request.body.refresh_token)) { throw new InvalidRequestError('Invalid parameter: `refresh_token`'); } @@ -142,7 +142,7 @@ RefreshTokenGrantType.prototype.revokeToken = function(token) { */ RefreshTokenGrantType.prototype.saveToken = function(user, client, scope) { - var fns = [ + const fns = [ this.generateAccessToken(client, user, scope), this.generateRefreshToken(client, user, scope), this.getAccessTokenExpiresAt(), @@ -152,7 +152,7 @@ RefreshTokenGrantType.prototype.saveToken = function(user, client, scope) { return Promise.all(fns) .bind(this) .spread(function(accessToken, refreshToken, accessTokenExpiresAt, refreshTokenExpiresAt) { - var token = { + const token = { accessToken: accessToken, accessTokenExpiresAt: accessTokenExpiresAt, scope: scope diff --git a/lib/handlers/authenticate-handler.js b/lib/handlers/authenticate-handler.js index dc9117b..b02b123 100644 --- a/lib/handlers/authenticate-handler.js +++ b/lib/handlers/authenticate-handler.js @@ -4,17 +4,17 @@ * Module dependencies. */ -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var InsufficientScopeError = require('../errors/insufficient-scope-error'); -var InvalidTokenError = require('../errors/invalid-token-error'); -var OAuthError = require('../errors/oauth-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -var Response = require('../response'); -var ServerError = require('../errors/server-error'); -var UnauthorizedRequestError = require('../errors/unauthorized-request-error'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const InsufficientScopeError = require('../errors/insufficient-scope-error'); +const InvalidTokenError = require('../errors/invalid-token-error'); +const OAuthError = require('../errors/oauth-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const Request = require('../request'); +const Response = require('../response'); +const ServerError = require('../errors/server-error'); +const UnauthorizedRequestError = require('../errors/unauthorized-request-error'); /** * Constructor. @@ -109,9 +109,9 @@ AuthenticateHandler.prototype.handle = function(request, response) { */ AuthenticateHandler.prototype.getTokenFromRequest = function(request) { - var headerToken = request.get('Authorization'); - var queryToken = request.query.access_token; - var bodyToken = request.body.access_token; + const headerToken = request.get('Authorization'); + const queryToken = request.query.access_token; + const bodyToken = request.body.access_token; if (!!headerToken + !!queryToken + !!bodyToken > 1) { throw new InvalidRequestError('Invalid request: only one authentication method is allowed'); @@ -139,8 +139,8 @@ AuthenticateHandler.prototype.getTokenFromRequest = function(request) { */ AuthenticateHandler.prototype.getTokenFromRequestHeader = function(request) { - var token = request.get('Authorization'); - var matches = token.match(/Bearer\s(\S+)/); + const token = request.get('Authorization'); + const matches = token.match(/Bearer\s(\S+)/); if (!matches) { throw new InvalidRequestError('Invalid request: malformed authorization header'); diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index 7cd89a1..b3f1d5e 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -4,29 +4,29 @@ * Module dependencies. */ -var AccessDeniedError = require('../errors/access-denied-error'); -var AuthenticateHandler = require('../handlers/authenticate-handler'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidClientError = require('../errors/invalid-client-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var InvalidScopeError = require('../errors/invalid-scope-error'); -var UnsupportedResponseTypeError = require('../errors/unsupported-response-type-error'); -var OAuthError = require('../errors/oauth-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -var Response = require('../response'); -var ServerError = require('../errors/server-error'); -var UnauthorizedClientError = require('../errors/unauthorized-client-error'); -var is = require('../validator/is'); -var tokenUtil = require('../utils/token-util'); -var url = require('url'); +const AccessDeniedError = require('../errors/access-denied-error'); +const AuthenticateHandler = require('../handlers/authenticate-handler'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidClientError = require('../errors/invalid-client-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const InvalidScopeError = require('../errors/invalid-scope-error'); +const UnsupportedResponseTypeError = require('../errors/unsupported-response-type-error'); +const OAuthError = require('../errors/oauth-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const Request = require('../request'); +const Response = require('../response'); +const ServerError = require('../errors/server-error'); +const UnauthorizedClientError = require('../errors/unauthorized-client-error'); +const isFormat = require('@node-oauth/formats'); +const tokenUtil = require('../utils/token-util'); +const url = require('url'); /** * Response types. */ -var responseTypes = { +const responseTypes = { code: require('../response-types/code-response-type'), //token: require('../response-types/token-response-type') }; @@ -81,7 +81,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { return Promise.reject(new AccessDeniedError('Access denied: user denied access to application')); } - var fns = [ + const fns = [ this.getAuthorizationCodeLifetime(), this.getClient(request), this.getUser(request, response) @@ -90,14 +90,20 @@ AuthorizeHandler.prototype.handle = function(request, response) { return Promise.all(fns) .bind(this) .spread(function(expiresAt, client, user) { - var uri = this.getRedirectUri(request, client); - var scope; - var state; - var ResponseType; + const uri = this.getRedirectUri(request, client); + let scope; + let state; + let ResponseType; return Promise.bind(this) .then(function() { - var requestedScope = this.getScope(request); + state = this.getState(request); + if(request.query.allowed === 'false') { + throw new AccessDeniedError('Access denied: user denied access to application'); + } + }) + .then(function() { + const requestedScope = this.getScope(request); return this.validateScope(user, client, requestedScope); }) @@ -107,14 +113,13 @@ AuthorizeHandler.prototype.handle = function(request, response) { return this.generateAuthorizationCode(client, user, scope); }) .then(function(authorizationCode) { - state = this.getState(request); ResponseType = this.getResponseType(request); return this.saveAuthorizationCode(authorizationCode, expiresAt, scope, client, uri, user); }) .then(function(code) { - var responseType = new ResponseType(code.authorizationCode); - var redirectUri = this.buildSuccessRedirectUri(uri, responseType); + const responseType = new ResponseType(code.authorizationCode); + const redirectUri = this.buildSuccessRedirectUri(uri, responseType); this.updateResponse(response, redirectUri, state); @@ -124,7 +129,7 @@ AuthorizeHandler.prototype.handle = function(request, response) { if (!(e instanceof OAuthError)) { e = new ServerError(e); } - var redirectUri = this.buildErrorRedirectUri(uri, e); + const redirectUri = this.buildErrorRedirectUri(uri, e); this.updateResponse(response, redirectUri, state); @@ -149,7 +154,7 @@ AuthorizeHandler.prototype.generateAuthorizationCode = function(client, user, sc */ AuthorizeHandler.prototype.getAuthorizationCodeLifetime = function() { - var expires = new Date(); + const expires = new Date(); expires.setSeconds(expires.getSeconds() + this.authorizationCodeLifetime); return expires; @@ -160,19 +165,20 @@ AuthorizeHandler.prototype.getAuthorizationCodeLifetime = function() { */ AuthorizeHandler.prototype.getClient = function(request) { - var clientId = request.body.client_id || request.query.client_id; + const self = this; + const clientId = request.body.client_id || request.query.client_id; if (!clientId) { throw new InvalidRequestError('Missing parameter: `client_id`'); } - if (!is.vschar(clientId)) { + if (!isFormat.vschar(clientId)) { throw new InvalidRequestError('Invalid parameter: `client_id`'); } - var redirectUri = request.body.redirect_uri || request.query.redirect_uri; + const redirectUri = request.body.redirect_uri || request.query.redirect_uri; - if (redirectUri && !is.uri(redirectUri)) { + if (redirectUri && !isFormat.uri(redirectUri)) { throw new InvalidRequestError('Invalid request: `redirect_uri` is not a valid URI'); } return promisify(this.model.getClient, 2).call(this.model, clientId, null) @@ -193,10 +199,17 @@ AuthorizeHandler.prototype.getClient = function(request) { throw new InvalidClientError('Invalid client: missing client `redirectUri`'); } - if (redirectUri && !client.redirectUris.includes(redirectUri)) { - throw new InvalidClientError('Invalid client: `redirect_uri` does not match client value'); + if (redirectUri) { + return self.validateRedirectUri(redirectUri, client) + .then(function(valid) { + if (!valid) { + throw new InvalidClientError('Invalid client: `redirect_uri` does not match client value'); + } + return client; + }); + } else { + return client; } - return client; }); }; @@ -223,9 +236,9 @@ AuthorizeHandler.prototype.validateScope = function(user, client, scope) { */ AuthorizeHandler.prototype.getScope = function(request) { - var scope = request.body.scope || request.query.scope; + const scope = request.body.scope || request.query.scope; - if (!is.nqschar(scope)) { + if (!isFormat.nqschar(scope)) { throw new InvalidScopeError('Invalid parameter: `scope`'); } @@ -237,14 +250,15 @@ AuthorizeHandler.prototype.getScope = function(request) { */ AuthorizeHandler.prototype.getState = function(request) { - var state = request.body.state || request.query.state; - - if (!this.allowEmptyState && !state) { - throw new InvalidRequestError('Missing parameter: `state`'); - } - - if (!is.vschar(state)) { - throw new InvalidRequestError('Invalid parameter: `state`'); + const state = request.body.state || request.query.state; + const stateExists = state && state.length > 0; + const stateIsValid = stateExists + ? isFormat.vschar(state) + : this.allowEmptyState; + + if (!stateIsValid) { + const message = (!stateExists) ? 'Missing' : 'Invalid'; + throw new InvalidRequestError(`${message} parameter: \`state\``); } return state; @@ -280,7 +294,7 @@ AuthorizeHandler.prototype.getRedirectUri = function(request, client) { */ AuthorizeHandler.prototype.saveAuthorizationCode = function(authorizationCode, expiresAt, scope, client, redirectUri, user) { - var code = { + const code = { authorizationCode: authorizationCode, expiresAt: expiresAt, redirectUri: redirectUri, @@ -289,12 +303,20 @@ AuthorizeHandler.prototype.saveAuthorizationCode = function(authorizationCode, e return promisify(this.model.saveAuthorizationCode, 3).call(this.model, code, client, user); }; + +AuthorizeHandler.prototype.validateRedirectUri = function(redirectUri, client) { + if (this.model.validateRedirectUri) { + return promisify(this.model.validateRedirectUri, 2).call(this.model, redirectUri, client); + } + + return Promise.resolve(client.redirectUris.includes(redirectUri)); +}; /** * Get response type. */ AuthorizeHandler.prototype.getResponseType = function(request) { - var responseType = request.body.response_type || request.query.response_type; + const responseType = request.body.response_type || request.query.response_type; if (!responseType) { throw new InvalidRequestError('Missing parameter: `response_type`'); @@ -320,7 +342,7 @@ AuthorizeHandler.prototype.buildSuccessRedirectUri = function(redirectUri, respo */ AuthorizeHandler.prototype.buildErrorRedirectUri = function(redirectUri, error) { - var uri = url.parse(redirectUri); + const uri = url.parse(redirectUri); uri.query = { error: error.name diff --git a/lib/handlers/token-handler.js b/lib/handlers/token-handler.js index 895ce2e..285843e 100644 --- a/lib/handlers/token-handler.js +++ b/lib/handlers/token-handler.js @@ -4,27 +4,27 @@ * Module dependencies. */ -var BearerTokenType = require('../token-types/bearer-token-type'); -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var InvalidClientError = require('../errors/invalid-client-error'); -var InvalidRequestError = require('../errors/invalid-request-error'); -var OAuthError = require('../errors/oauth-error'); -var Promise = require('bluebird'); -var promisify = require('promisify-any').use(Promise); -var Request = require('../request'); -var Response = require('../response'); -var ServerError = require('../errors/server-error'); -var TokenModel = require('../models/token-model'); -var UnauthorizedClientError = require('../errors/unauthorized-client-error'); -var UnsupportedGrantTypeError = require('../errors/unsupported-grant-type-error'); -var auth = require('basic-auth'); -var is = require('../validator/is'); +const BearerTokenType = require('../token-types/bearer-token-type'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidClientError = require('../errors/invalid-client-error'); +const InvalidRequestError = require('../errors/invalid-request-error'); +const OAuthError = require('../errors/oauth-error'); +const Promise = require('bluebird'); +const promisify = require('promisify-any').use(Promise); +const Request = require('../request'); +const Response = require('../response'); +const ServerError = require('../errors/server-error'); +const TokenModel = require('../models/token-model'); +const UnauthorizedClientError = require('../errors/unauthorized-client-error'); +const UnsupportedGrantTypeError = require('../errors/unsupported-grant-type-error'); +const auth = require('basic-auth'); +const isFormat = require('@node-oauth/formats'); /** * Grant types. */ -var grantTypes = { +const grantTypes = { authorization_code: require('../grant-types/authorization-code-grant-type'), client_credentials: require('../grant-types/client-credentials-grant-type'), password: require('../grant-types/password-grant-type'), @@ -92,8 +92,8 @@ TokenHandler.prototype.handle = function(request, response) { return this.handleGrantType(request, client); }) .tap(function(data) { - var model = new TokenModel(data, {allowExtendedTokenAttributes: this.allowExtendedTokenAttributes}); - var tokenType = this.getTokenType(model); + const model = new TokenModel(data, {allowExtendedTokenAttributes: this.allowExtendedTokenAttributes}); + const tokenType = this.getTokenType(model); this.updateSuccessResponse(response, tokenType); }).catch(function(e) { @@ -112,8 +112,8 @@ TokenHandler.prototype.handle = function(request, response) { */ TokenHandler.prototype.getClient = function(request, response) { - var credentials = this.getClientCredentials(request); - var grantType = request.body.grant_type; + const credentials = this.getClientCredentials(request); + const grantType = request.body.grant_type; if (!credentials.clientId) { throw new InvalidRequestError('Missing parameter: `client_id`'); @@ -123,11 +123,11 @@ TokenHandler.prototype.getClient = function(request, response) { throw new InvalidRequestError('Missing parameter: `client_secret`'); } - if (!is.vschar(credentials.clientId)) { + if (!isFormat.vschar(credentials.clientId)) { throw new InvalidRequestError('Invalid parameter: `client_id`'); } - if (credentials.clientSecret && !is.vschar(credentials.clientSecret)) { + if (credentials.clientSecret && !isFormat.vschar(credentials.clientSecret)) { throw new InvalidRequestError('Invalid parameter: `client_secret`'); } @@ -172,8 +172,8 @@ TokenHandler.prototype.getClient = function(request, response) { */ TokenHandler.prototype.getClientCredentials = function(request) { - var credentials = auth(request); - var grantType = request.body.grant_type; + const credentials = auth(request); + const grantType = request.body.grant_type; if (credentials) { return { clientId: credentials.name, clientSecret: credentials.pass }; @@ -197,13 +197,13 @@ TokenHandler.prototype.getClientCredentials = function(request) { */ TokenHandler.prototype.handleGrantType = function(request, client) { - var grantType = request.body.grant_type; + const grantType = request.body.grant_type; if (!grantType) { throw new InvalidRequestError('Missing parameter: `grant_type`'); } - if (!is.nchar(grantType) && !is.uri(grantType)) { + if (!isFormat.nchar(grantType) && !isFormat.uri(grantType)) { throw new InvalidRequestError('Invalid parameter: `grant_type`'); } @@ -215,11 +215,11 @@ TokenHandler.prototype.handleGrantType = function(request, client) { throw new UnauthorizedClientError('Unauthorized client: `grant_type` is invalid'); } - var accessTokenLifetime = this.getAccessTokenLifetime(client); - var refreshTokenLifetime = this.getRefreshTokenLifetime(client); - var Type = this.grantTypes[grantType]; + const accessTokenLifetime = this.getAccessTokenLifetime(client); + const refreshTokenLifetime = this.getRefreshTokenLifetime(client); + const Type = this.grantTypes[grantType]; - var options = { + const options = { accessTokenLifetime: accessTokenLifetime, model: this.model, refreshTokenLifetime: refreshTokenLifetime, diff --git a/lib/models/token-model.js b/lib/models/token-model.js index 37bb133..473c7ac 100644 --- a/lib/models/token-model.js +++ b/lib/models/token-model.js @@ -4,13 +4,13 @@ * Module dependencies. */ -var InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); /** * Constructor. */ -var modelAttributes = ['accessToken', 'accessTokenExpiresAt', 'refreshToken', 'refreshTokenExpiresAt', 'scope', 'client', 'user']; +const modelAttributes = ['accessToken', 'accessTokenExpiresAt', 'refreshToken', 'refreshTokenExpiresAt', 'scope', 'client', 'user']; function TokenModel(data, options) { data = data || {}; @@ -46,7 +46,7 @@ function TokenModel(data, options) { if (options && options.allowExtendedTokenAttributes) { this.customAttributes = {}; - for (var key in data) { + for (const key in data) { if ( Object.prototype.hasOwnProperty.call(data, key) && (modelAttributes.indexOf(key) < 0)) { this.customAttributes[key] = data[key]; } diff --git a/lib/request.js b/lib/request.js index 00b8795..560b29b 100644 --- a/lib/request.js +++ b/lib/request.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var InvalidArgumentError = require('./errors/invalid-argument-error'); -var typeis = require('type-is'); +const InvalidArgumentError = require('./errors/invalid-argument-error'); +const typeis = require('type-is'); /** * Constructor. @@ -32,14 +32,14 @@ function Request(options) { this.query = options.query; // Store the headers in lower case. - for (var field in options.headers) { + for (const field in options.headers) { if (Object.prototype.hasOwnProperty.call(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the request object passed in - for (var property in options) { + for (const property in options) { if (Object.prototype.hasOwnProperty.call(options, property) && !this[property]) { this[property] = options[property]; } diff --git a/lib/response-types/code-response-type.js b/lib/response-types/code-response-type.js index 6eaf23a..8252248 100644 --- a/lib/response-types/code-response-type.js +++ b/lib/response-types/code-response-type.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var InvalidArgumentError = require('../errors/invalid-argument-error'); -var url = require('url'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); +const url = require('url'); /** * Constructor. @@ -28,7 +28,7 @@ CodeResponseType.prototype.buildRedirectUri = function(redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); } - var uri = url.parse(redirectUri, true); + const uri = url.parse(redirectUri, true); uri.query.code = this.code; uri.search = null; diff --git a/lib/response-types/token-response-type.js b/lib/response-types/token-response-type.js index 2637f64..29c32e7 100644 --- a/lib/response-types/token-response-type.js +++ b/lib/response-types/token-response-type.js @@ -4,7 +4,7 @@ * Module dependencies. */ -var ServerError = require('../errors/server-error'); +const ServerError = require('../errors/server-error'); /** * Constructor. diff --git a/lib/response.js b/lib/response.js index 76fe854..29a2c51 100644 --- a/lib/response.js +++ b/lib/response.js @@ -12,14 +12,14 @@ function Response(options) { this.status = 200; // Store the headers in lower case. - for (var field in options.headers) { + for (const field in options.headers) { if (Object.prototype.hasOwnProperty.call(options.headers, field)) { this.headers[field.toLowerCase()] = options.headers[field]; } } // Store additional properties of the response object passed in - for (var property in options) { + for (const property in options) { if (Object.prototype.hasOwnProperty.call(options, property) && !this[property]) { this[property] = options[property]; } diff --git a/lib/server.js b/lib/server.js index a588f80..53bbd2a 100644 --- a/lib/server.js +++ b/lib/server.js @@ -4,10 +4,10 @@ * Module dependencies. */ -var AuthenticateHandler = require('./handlers/authenticate-handler'); -var AuthorizeHandler = require('./handlers/authorize-handler'); -var InvalidArgumentError = require('./errors/invalid-argument-error'); -var TokenHandler = require('./handlers/token-handler'); +const AuthenticateHandler = require('./handlers/authenticate-handler'); +const AuthorizeHandler = require('./handlers/authorize-handler'); +const InvalidArgumentError = require('./errors/invalid-argument-error'); +const TokenHandler = require('./handlers/token-handler'); /** * Constructor. diff --git a/lib/token-types/bearer-token-type.js b/lib/token-types/bearer-token-type.js index 9440849..0bf526d 100644 --- a/lib/token-types/bearer-token-type.js +++ b/lib/token-types/bearer-token-type.js @@ -4,7 +4,7 @@ * Module dependencies. */ -var InvalidArgumentError = require('../errors/invalid-argument-error'); +const InvalidArgumentError = require('../errors/invalid-argument-error'); /** * Constructor. @@ -30,7 +30,7 @@ function BearerTokenType(accessToken, accessTokenLifetime, refreshToken, scope, */ BearerTokenType.prototype.valueOf = function() { - var object = { + const object = { access_token: this.accessToken, token_type: 'Bearer' }; @@ -47,7 +47,7 @@ BearerTokenType.prototype.valueOf = function() { object.scope = this.scope; } - for (var key in this.customAttributes) { + for (const key in this.customAttributes) { if ( Object.prototype.hasOwnProperty.call(this.customAttributes, key) ) { object[key] = this.customAttributes[key]; } diff --git a/lib/token-types/mac-token-type.js b/lib/token-types/mac-token-type.js index 9fdc600..a5dd240 100644 --- a/lib/token-types/mac-token-type.js +++ b/lib/token-types/mac-token-type.js @@ -4,7 +4,7 @@ * Module dependencies. */ -var ServerError = require('../errors/server-error'); +const ServerError = require('../errors/server-error'); /** * Constructor. diff --git a/lib/utils/token-util.js b/lib/utils/token-util.js index 96d05c0..a66e252 100644 --- a/lib/utils/token-util.js +++ b/lib/utils/token-util.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var crypto = require('crypto'); -var randomBytes = require('bluebird').promisify(require('crypto').randomBytes); +const crypto = require('crypto'); +const randomBytes = require('bluebird').promisify(require('crypto').randomBytes); /** * Export `TokenUtil`. diff --git a/lib/validator/is.js b/lib/validator/is.js index a240e93..4bb58c5 100644 --- a/lib/validator/is.js +++ b/lib/validator/is.js @@ -5,7 +5,7 @@ * Validation rules. */ -var rules = { +const rules = { NCHAR: /^[\u002D\u002E\u005F\w]+$/, NQCHAR: /^[\u0021\u0023-\u005B\u005D-\u007E]+$/, NQSCHAR: /^[\u0020-\u0021\u0023-\u005B\u005D-\u007E]+$/, diff --git a/package-lock.json b/package-lock.json index c04ae94..19a704e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@node-oauth/oauth2-server", - "version": "4.0.0", + "version": "4.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -304,71 +304,31 @@ } }, "@eslint/eslintrc": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.2.tgz", - "integrity": "sha512-x1ZXdEFsvTcnbTZgqcWUL9w2ybgZCw/qbKTPQnab+XnYA2bMQpJCh+/bBzCRfDJaJdlrrQlOk49jNtru9gL/6Q==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", + "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.0.0", + "espree": "^9.2.0", "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -378,37 +338,20 @@ } }, "@humanwhocodes/config-array": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", - "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", + "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -494,6 +437,11 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@node-oauth/formats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@node-oauth/formats/-/formats-1.0.0.tgz", + "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==" + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -504,9 +452,9 @@ } }, "@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" @@ -536,9 +484,9 @@ "dev": true }, "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", + "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", "dev": true }, "acorn-jsx": { @@ -975,13 +923,13 @@ "dev": true }, "eslint": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.0.0.tgz", - "integrity": "sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-TxU/p7LB1KxQ6+7aztTnO7K0i+h0tDi81YRY9VzB6Id71kNz+fFYnf5HD5UOQmxkzcoa0TlVZf9dpMtUv0GpWg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.0.2", - "@humanwhocodes/config-array": "^0.6.0", + "@eslint/eslintrc": "^1.0.5", + "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -989,10 +937,10 @@ "doctrine": "^3.0.0", "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^6.0.0", + "eslint-scope": "^7.1.0", "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.0.0", - "espree": "^9.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.2.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1014,97 +962,21 @@ "progress": "^2.0.0", "regexpp": "^3.2.0", "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -1114,21 +986,6 @@ "lru-cache": "^6.0.0" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -1138,9 +995,9 @@ } }, "eslint-scope": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", - "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", "dev": true, "requires": { "esrecurse": "^4.3.0", @@ -1165,20 +1022,20 @@ } }, "eslint-visitor-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", - "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", "dev": true }, "espree": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz", - "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.2.0.tgz", + "integrity": "sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==", "dev": true, "requires": { - "acorn": "^8.5.0", + "acorn": "^8.6.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.0.0" + "eslint-visitor-keys": "^3.1.0" } }, "esprima": { @@ -1206,9 +1063,9 @@ } }, "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true }, "esutils": { @@ -1291,9 +1148,9 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, "foreground-child": { @@ -1875,6 +1732,17 @@ "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + } } }, "node-preload": { @@ -2363,13 +2231,13 @@ "dev": true }, "sinon": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz", - "integrity": "sha512-59237HChms4kg7/sXhiRcUzdSkKuydDeTiamT/jesUVHshBgL8XAmhgFo0GfK6RruMDM/iRSij1EybmMog9cJw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz", + "integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==", "dev": true, "requires": { "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": "^7.1.2", + "@sinonjs/fake-timers": "^8.1.0", "@sinonjs/samsam": "^6.0.2", "diff": "^5.0.0", "nise": "^5.1.0", diff --git a/package.json b/package.json index 04999c5..c0deb37 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@node-oauth/oauth2-server", "description": "Complete, framework-agnostic, compliant and well tested module for implementing an OAuth2 Server in node.js", - "version": "4.0.0", + "version": "4.1.1", "keywords": [ "oauth", "oauth2" @@ -17,7 +17,14 @@ "Daniel Reguero" ], "main": "index.js", + "types": "index.d.ts", + "files": [ + "index.js", + "index.d.ts", + "lib" + ], "dependencies": { + "@node-oauth/formats": "^1.0.0", "basic-auth": "2.0.1", "bluebird": "3.7.2", "promisify-any": "2.0.1", @@ -28,7 +35,7 @@ "eslint": "^8.0.0", "mocha": "^9.1.2", "nyc": "^15.1.0", - "sinon": "^11.1.2" + "sinon": "^12.0.1" }, "license": "MIT", "engines": { @@ -38,7 +45,10 @@ "pretest": "./node_modules/.bin/eslint lib test index.js", "test": "NODE_ENV=test ./node_modules/.bin/mocha 'test/**/*_test.js'", "test-debug": "NODE_ENV=test ./node_modules/.bin/mocha --inspect --debug-brk 'test/**/*_test.js'", - "test:coverage": "NODE_ENV=test nyc --reporter=html --reporter=text ./node_modules/.bin/mocha 'test/**/*_test.js'" + "test:watch": "NODE_ENV=test ./node_modules/.bin/mocha --watch 'test/**/*_test.js'", + "test:coverage": "NODE_ENV=test nyc --reporter=html --reporter=text ./node_modules/.bin/mocha 'test/**/*_test.js'", + "lint": "npx eslint .", + "lint:fix": "npx eslint . --fix" }, "repository": { "type": "git", diff --git a/test/assertions.js b/test/assertions.js index 7ebf85f..7a95c80 100644 --- a/test/assertions.js +++ b/test/assertions.js @@ -4,7 +4,7 @@ * Module dependencies. */ -var chai = require('chai'); +const chai = require('chai'); /** * SHA-256 assertion. @@ -12,7 +12,7 @@ var chai = require('chai'); chai.use(function (_chai, utils) { chai.Assertion.addMethod('sha256', function (...args) { - var obj = utils.flag(this, 'object'); + const obj = utils.flag(this, 'object'); new chai.Assertion(obj).match(/^[a-f0-9]{64}$/i); }); }); diff --git a/test/compliance/client-authentication_test.js b/test/compliance/client-authentication_test.js new file mode 100644 index 0000000..72624ec --- /dev/null +++ b/test/compliance/client-authentication_test.js @@ -0,0 +1,128 @@ +/** + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1 + * + * For example (with extra line breaks for display purposes only): + * + * Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3 + * + * Alternatively, the authorization server MAY support including the + * client credentials in the request-body using the following + * parameters: + * + * client_id + * REQUIRED. The client identifier issued to the client during + * the registration process described by Section 2.2. + * + * client_secret + * REQUIRED. The client secret. The client MAY omit the + * parameter if the client secret is an empty string. + */ + +const OAuth2Server = require('../..'); +const DB = require('../helpers/db'); +const createModel = require('../helpers/model'); +const createRequest = require('../helpers/request'); +const Response = require('../../lib/response'); + +require('chai').should(); + +const db = new DB(); + +const auth = new OAuth2Server({ + model: createModel(db) +}); + +const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); +const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password'] }); +const scope = 'read write'; + +function createDefaultRequest () { + return createRequest({ + body: { + grant_type: 'password', + username: user.username, + password: user.password, + scope + }, + headers: { + 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + }); +} + +describe('Client Authentication Compliance', function () { + describe('No authentication', function () { + it('should be an unsuccesfull authentication', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.headers.authorization; + + await auth.token(request, response, {}) + .then((token) => { + throw new Error('Should not be here'); + }). + catch(err => { + err.name.should.equal('invalid_client'); + }); + }); + }); + + describe('Basic Authentication', function () { + it('should be a succesfull authentication', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + await auth.token(request, response, {}); + }); + + it('should be an unsuccesfull authentication', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + request.headers.authorization = 'Basic ' + Buffer.from('a:c').toString('base64'); + + await auth.token(request, response, {}) + .then((token) => { + throw new Error('Should not be here'); + }). + catch(err => { + err.name.should.equal('invalid_client'); + }); + }); + }); + + describe('Request body authentication', function () { + it('should be a succesfull authentication', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.headers.authorization; + + request.body.client_id = client.id; + request.body.client_secret = client.secret; + + await auth.token(request, response, {}); + }); + + it('should be an unsuccesfull authentication', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.headers.authorization; + + request.body.client_id = 'a'; + request.body.client_secret = 'c'; + + await auth.token(request, response, {}) + .then((token) => { + throw new Error('Should not be here'); + }) + .catch(err => { + err.name.should.equal('invalid_client'); + }); + }); + }); +}); diff --git a/test/compliance/password-grant-type_test.js b/test/compliance/password-grant-type_test.js new file mode 100644 index 0000000..7941d54 --- /dev/null +++ b/test/compliance/password-grant-type_test.js @@ -0,0 +1,236 @@ +/** + * Request + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.3.2 + * + * grant_type + * REQUIRED. Value MUST be set to "password". + * username + * REQUIRED. The resource owner username. + * password + * REQUIRED. The resource owner password. + * scope + * OPTIONAL. The scope of the access request as described by Section 3.3. + */ + +/** + * Response + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 + * + * access_token + * REQUIRED. The access token issued by the authorization server. + * token_type + * REQUIRED. The type of the token issued as described in + * Section 7.1. Value is case insensitive. + * expires_in + * RECOMMENDED. The lifetime in seconds of the access token. For + * example, the value "3600" denotes that the access token will + * expire in one hour from the time the response was generated. + * If omitted, the authorization server SHOULD provide the + * expiration time via other means or document the default value. + * refresh_token + * OPTIONAL. The refresh token, which can be used to obtain new + * access tokens using the same authorization grant as described + * in Section 6. + * scope + * OPTIONAL, if identical to the scope requested by the client; + * otherwise, REQUIRED. The scope of the access token as + * described by Section 3.3. + */ + +/** + * Response (error) + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 + * + * error + * REQUIRED. A single ASCII [USASCII] error code from the following: + * invalid_request, invalid_client, invalid_grant + * unauthorized_client, unsupported_grant_type, invalid_scope + * error_description + * OPTIONAL. Human-readable ASCII [USASCII] text providing + * additional information, used to assist the client developer in + * understanding the error that occurred. + * error_uri + * OPTIONAL. A URI identifying a human-readable web page with + * information about the error, used to provide the client + * developer with additional information about the error. + */ + +const OAuth2Server = require('../..'); +const DB = require('../helpers/db'); +const createModel = require('../helpers/model'); +const createRequest = require('../helpers/request'); +const Response = require('../../lib/response'); +const crypto = require('crypto'); + +require('chai').should(); + +const db = new DB(); + +const auth = new OAuth2Server({ + model: createModel(db) +}); + +const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); +const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password'] }); +const scope = 'read write'; + +function createDefaultRequest () { + return createRequest({ + body: { + grant_type: 'password', + username: user.username, + password: user.password, + scope + }, + headers: { + 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + }); +} + +describe('PasswordGrantType Compliance', function () { + describe('Authenticate', function () { + it ('Succesfull authorization', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + const token = await auth.token(request, response, {}); + response.body.token_type.should.equal('Bearer'); + response.body.access_token.should.equal(token.accessToken); + response.body.refresh_token.should.equal(token.refreshToken); + response.body.expires_in.should.be.a('number'); + response.body.scope.should.equal(scope); + + token.accessToken.should.be.a('string'); + token.refreshToken.should.be.a('string'); + token.accessTokenExpiresAt.should.be.a('date'); + token.refreshTokenExpiresAt.should.be.a('date'); + token.scope.should.equal(scope); + + db.accessTokens.has(token.accessToken).should.equal(true); + db.refreshTokens.has(token.refreshToken).should.equal(true); + }); + + it ('Succesfull authorization and authentication', async function () { + const tokenRequest = createDefaultRequest(); + const tokenResponse = new Response({}); + + const token = await auth.token(tokenRequest, tokenResponse, {}); + + const authenticationRequest = createRequest({ + body: {}, + headers: { + 'Authorization': `Bearer ${token.accessToken}` + }, + method: 'GET', + query: {} + }); + const authenticationResponse = new Response({}); + + const authenticated = await auth.authenticate( + authenticationRequest, + authenticationResponse, + {}); + + authenticated.scope.should.equal(scope); + authenticated.user.should.be.an('object'); + authenticated.client.should.be.an('object'); + }); + + it ('Username missing', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.body.username; + + await auth.token(request, response, {}) + .catch(err => { + err.name.should.equal('invalid_request'); + }); + }); + + it ('Password missing', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.body.password; + + await auth.token(request, response, {}) + .catch(err => { + err.name.should.equal('invalid_request'); + }); + }); + + it ('Wrong username', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + request.body.username = 'wrong'; + + await auth.token(request, response, {}) + .catch(err => { + err.name.should.equal('invalid_grant'); + }); + }); + + it ('Wrong password', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + request.body.password = 'wrong'; + + await auth.token(request, response, {}) + .catch(err => { + err.name.should.equal('invalid_grant'); + }); + }); + + it ('Client not found', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + const clientId = crypto.randomBytes(4).toString('hex'); + const clientSecret = crypto.randomBytes(4).toString('hex'); + + request.headers.authorization = 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); + + await auth.token(request, response, {}) + .catch(err => { + err.name.should.equal('invalid_client'); + }); + }); + + it ('Client secret not required', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.body.client_secret; + + const token = await auth.token(request, response, { + requireClientAuthentication: { + password: false + } + }); + + token.accessToken.should.be.a('string'); + }); + + it ('Client secret required', async function () { + const request = createDefaultRequest(); + const response = new Response({}); + + delete request.body.client_secret; + + await auth.token(request, response, { + requireClientAuthentication: { + password: false + } + }) + .catch(err => { + err.name.should.equal('invalid_client'); + }); + }); + }); +}); diff --git a/test/compliance/refresh-token-grant-type_test.js b/test/compliance/refresh-token-grant-type_test.js new file mode 100644 index 0000000..b01fef3 --- /dev/null +++ b/test/compliance/refresh-token-grant-type_test.js @@ -0,0 +1,173 @@ +/** + * Request an access token using the refresh token grant type. + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-6 + * + * grant_type + * REQUIRED. Value MUST be set to "refresh_token". + * refresh_token + * REQUIRED. The refresh token issued to the client. + * scope + * OPTIONAL. The scope of the access request as described by + * Section 3.3. The requested scope MUST NOT include any scope + * not originally granted by the resource owner, and if omitted is + * treated as equal to the scope originally granted by the + * resource owner. + */ + + +/** + * Response + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 + * + * access_token + * REQUIRED. The access token issued by the authorization server. + * token_type + * REQUIRED. The type of the token issued as described in + * Section 7.1. Value is case insensitive. + * expires_in + * RECOMMENDED. The lifetime in seconds of the access token. For + * example, the value "3600" denotes that the access token will + * expire in one hour from the time the response was generated. + * If omitted, the authorization server SHOULD provide the + * expiration time via other means or document the default value. + * refresh_token + * OPTIONAL. The refresh token, which can be used to obtain new + * access tokens using the same authorization grant as described + * in Section 6. + * scope + * OPTIONAL, if identical to the scope requested by the client; + * otherwise, REQUIRED. The scope of the access token as + * described by Section 3.3. + */ + +/** + * Response (error) + * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 + * + * error + * REQUIRED. A single ASCII [USASCII] error code from the following: + * invalid_request, invalid_client, invalid_grant + * unauthorized_client, unsupported_grant_type, invalid_scope + * error_description + * OPTIONAL. Human-readable ASCII [USASCII] text providing + * additional information, used to assist the client developer in + * understanding the error that occurred. + * error_uri + * OPTIONAL. A URI identifying a human-readable web page with + * information about the error, used to provide the client + * developer with additional information about the error. + */ +const OAuth2Server = require('../..'); +const DB = require('../helpers/db'); +const createModel = require('../helpers/model'); +const createRequest = require('../helpers/request'); +const Response = require('../../lib/response'); + +require('chai').should(); + +const db = new DB(); + +const auth = new OAuth2Server({ + model: createModel(db) +}); + +const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); +const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password', 'refresh_token'] }); +const scope = 'read write'; + +function createLoginRequest () { + return createRequest({ + body: { + grant_type: 'password', + username: user.username, + password: user.password, + scope + }, + headers: { + 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + 'content-type': 'application/x-www-form-urlencoded' + }, + method: 'POST', + }); +} + +function createRefreshRequest (refresh_token) { + return createRequest({ + method: 'POST', + body: { + grant_type: 'refresh_token', + refresh_token, + scope + }, + headers: { + 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + 'content-type': 'application/x-www-form-urlencoded' + } + }); +} + +describe('RefreshTokenGrantType Compliance', function () { + describe('With scope', function () { + it('Should generate token response', async function () { + const request = createLoginRequest(); + const response = new Response({}); + + const credentials = await auth.token(request, response, {}); + + const refreshRequest = createRefreshRequest(credentials.refreshToken); + const refreshResponse = new Response({}); + + const token = await auth.token(refreshRequest, refreshResponse, {}); + + refreshResponse.body.token_type.should.equal('Bearer'); + refreshResponse.body.access_token.should.equal(token.accessToken); + refreshResponse.body.refresh_token.should.equal(token.refreshToken); + refreshResponse.body.expires_in.should.be.a('number'); + refreshResponse.body.scope.should.equal(scope); + + token.accessToken.should.be.a('string'); + token.refreshToken.should.be.a('string'); + token.accessTokenExpiresAt.should.be.a('date'); + token.refreshTokenExpiresAt.should.be.a('date'); + token.scope.should.equal(scope); + + db.accessTokens.has(token.accessToken).should.equal(true); + db.refreshTokens.has(token.refreshToken).should.equal(true); + }); + + it('Should throw invalid_grant error', async function () { + const request = createRefreshRequest('invalid'); + const response = new Response({}); + + await auth.token(request, response, {}) + .then(() => { + throw Error('Should not reach this'); + }).catch(err => { + err.name.should.equal('invalid_grant'); + }); + }); + + // TODO: test refresh token with different scopes + // https://github.com/node-oauth/node-oauth2-server/issues/104 + + // it('Should throw invalid_scope error', async function () { + // const request = createLoginRequest(); + // const response = new Response({}); + + // const credentials = await auth.token(request, response, {}); + + // const refreshRequest = createRefreshRequest(credentials.refreshToken); + // const refreshResponse = new Response({}); + + // refreshRequest.scope = 'invalid'; + + // await auth.token(refreshRequest, refreshResponse, {}) + // .then(() => { + // throw Error('Should not reach this'); + // }) + // .catch(err => { + // err.name.should.equal('invalid_scope'); + // }); + // }); + }); +}); diff --git a/test/helpers/db.js b/test/helpers/db.js new file mode 100644 index 0000000..147d174 --- /dev/null +++ b/test/helpers/db.js @@ -0,0 +1,70 @@ +class DB { + constructor () { + this.users = new Map(); + this.clients = []; + this.accessTokens = new Map(); + this.refreshTokens= new Map(); + } + + saveUser (user) { + this.users.set(user.id, user); + + return user; + } + + findUser (username, password) { + return Array.from(this.users.values()).find(user => { + return user.username === username && user.password === password; + }); + } + + findUserById (id) { + return this.users.get(id); + } + + saveClient (client) { + this.clients.push(client); + + return client; + } + + findClient (clientId, clientSecret) { + return this.clients.find(client => { + if (clientSecret) { + return client.id === clientId && client.secret === clientSecret; + } else { + return client.id === clientId; + } + }); + } + + findClientById (id) { + return this.clients.find(client => client.id === id); + } + + saveAccessToken (accessToken, meta) { + this.accessTokens.set(accessToken, meta); + } + + findAccessToken (accessToken) { + return this.accessTokens.get(accessToken); + } + + deleteAccessToken (accessToken) { + this.accessTokens.delete(accessToken); + } + + saveRefreshToken (refreshToken, meta) { + this.refreshTokens.set(refreshToken, meta); + } + + findRefreshToken (refreshToken) { + return this.refreshTokens.get(refreshToken); + } + + deleteRefreshToken (refreshToken) { + this.refreshTokens.delete(refreshToken); + } +} + +module.exports = DB; diff --git a/test/helpers/model.js b/test/helpers/model.js new file mode 100644 index 0000000..7a1893b --- /dev/null +++ b/test/helpers/model.js @@ -0,0 +1,92 @@ +const scopes = ['read', 'write']; + +function createModel (db) { + async function getUser (username, password) { + return db.findUser(username, password); + } + + async function getClient (clientId, clientSecret) { + return db.findClient(clientId, clientSecret); + } + + async function saveToken (token, client, user) { + const meta = { + clientId: client.id, + userId: user.id, + scope: token.scope, + accessTokenExpiresAt: token.accessTokenExpiresAt, + refreshTokenExpiresAt: token.refreshTokenExpiresAt + }; + + token.client = client; + token.user = user; + + if (token.accessToken) { + db.saveAccessToken(token.accessToken, meta); + } + + if (token.refreshToken) { + db.saveRefreshToken(token.refreshToken, meta); + } + + return token; + } + + async function getAccessToken (accessToken) { + const meta = db.findAccessToken(accessToken); + + if (!meta) { + return false; + } + + return { + accessToken, + accessTokenExpiresAt: meta.accessTokenExpiresAt, + user: db.findUserById(meta.userId), + client: db.findClientById(meta.clientId), + scope: meta.scope + }; + } + + async function getRefreshToken (refreshToken) { + const meta = db.findRefreshToken(refreshToken); + + if (!meta) { + return false; + } + + return { + refreshToken, + refreshTokenExpiresAt: meta.refreshTokenExpiresAt, + user: db.findUserById(meta.userId), + client: db.findClientById(meta.clientId), + scope: meta.scope + }; + } + + async function revokeToken (token) { + db.deleteRefreshToken(token.refreshToken); + + return true; + } + + async function verifyScope (token, scope) { + if (typeof scope === 'string') { + return scopes.includes(scope); + } else { + return scope.every(s => scopes.includes(s)); + } + } + + return { + getUser, + getClient, + saveToken, + getAccessToken, + getRefreshToken, + revokeToken, + verifyScope + }; +} + +module.exports = createModel; diff --git a/test/helpers/request.js b/test/helpers/request.js new file mode 100644 index 0000000..be556a8 --- /dev/null +++ b/test/helpers/request.js @@ -0,0 +1,17 @@ +const Request = require('../../lib/request'); + +module.exports = (request) => { + const req = new Request({ + query: {}, + body: {}, + headers: {}, + method: 'GET', + ...request + }); + + req.is = function (header) { + return this.headers['content-type'] === header; + }; + + return req; +}; diff --git a/test/integration/grant-types/abstract-grant-type_test.js b/test/integration/grant-types/abstract-grant-type_test.js index 160ba21..a6c4d2b 100644 --- a/test/integration/grant-types/abstract-grant-type_test.js +++ b/test/integration/grant-types/abstract-grant-type_test.js @@ -4,11 +4,11 @@ * Module dependencies. */ -var AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('chai').should(); +const AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const should = require('chai').should(); /** * Test `AbstractGrantType` integration. @@ -39,20 +39,20 @@ describe('AbstractGrantType integration', function() { }); it('should set the `accessTokenLifetime`', function() { - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {} }); + const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {} }); grantType.accessTokenLifetime.should.equal(123); }); it('should set the `model`', function() { - var model = {}; - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: model }); + const model = {}; + const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: model }); grantType.model.should.equal(model); }); it('should set the `refreshTokenLifetime`', function() { - var grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); grantType.refreshTokenLifetime.should.equal(456); }); @@ -60,7 +60,7 @@ describe('AbstractGrantType integration', function() { describe('generateAccessToken()', function() { it('should return an access token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); return handler.generateAccessToken() .then(function(data) { @@ -70,23 +70,23 @@ describe('AbstractGrantType integration', function() { }); it('should support promises', function() { - var model = { + const model = { generateAccessToken: function() { return Promise.resolve({}); } }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); handler.generateAccessToken().should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { generateAccessToken: function() { return {}; } }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); handler.generateAccessToken().should.be.an.instanceOf(Promise); }); @@ -94,7 +94,7 @@ describe('AbstractGrantType integration', function() { describe('generateRefreshToken()', function() { it('should return a refresh token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); return handler.generateRefreshToken() .then(function(data) { @@ -104,23 +104,23 @@ describe('AbstractGrantType integration', function() { }); it('should support promises', function() { - var model = { + const model = { generateRefreshToken: function() { return Promise.resolve({}); } }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); handler.generateRefreshToken().should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { generateRefreshToken: function() { return {}; } }; - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); handler.generateRefreshToken().should.be.an.instanceOf(Promise); }); @@ -128,7 +128,7 @@ describe('AbstractGrantType integration', function() { describe('getAccessTokenExpiresAt()', function() { it('should return a date', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); handler.getAccessTokenExpiresAt().should.be.an.instanceOf(Date); }); @@ -136,7 +136,7 @@ describe('AbstractGrantType integration', function() { describe('getRefreshTokenExpiresAt()', function() { it('should return a refresh token', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); handler.getRefreshTokenExpiresAt().should.be.an.instanceOf(Date); }); @@ -144,8 +144,8 @@ describe('AbstractGrantType integration', function() { describe('getScope()', function() { it('should throw an error if `scope` is invalid', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { handler.getScope(request); @@ -158,15 +158,15 @@ describe('AbstractGrantType integration', function() { }); it('should allow the `scope` to be `undefined`', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); should.not.exist(handler.getScope(request)); }); it('should return the scope', function() { - var handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - var request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); + const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); handler.getScope(request).should.equal('foo'); }); diff --git a/test/integration/grant-types/authorization-code-grant-type_test.js b/test/integration/grant-types/authorization-code-grant-type_test.js index 417a23a..6cddd53 100644 --- a/test/integration/grant-types/authorization-code-grant-type_test.js +++ b/test/integration/grant-types/authorization-code-grant-type_test.js @@ -4,14 +4,14 @@ * Module dependencies. */ -var AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var ServerError = require('../../../lib/errors/server-error'); -var should = require('chai').should(); +const AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const ServerError = require('../../../lib/errors/server-error'); +const should = require('chai').should(); /** * Test `AuthorizationCodeGrantType` integration. @@ -43,7 +43,7 @@ describe('AuthorizationCodeGrantType integration', function() { it('should throw an error if the model does not implement `revokeAuthorizationCode()`', function() { try { - var model = { + const model = { getAuthorizationCode: function() {} }; @@ -58,7 +58,7 @@ describe('AuthorizationCodeGrantType integration', function() { it('should throw an error if the model does not implement `saveToken()`', function() { try { - var model = { + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {} }; @@ -75,12 +75,12 @@ describe('AuthorizationCodeGrantType integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); try { grantType.handle(); @@ -93,14 +93,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `client` is invalid', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, expiresAt: new Date(new Date() * 2), user: {} }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.handle(request, client) .then(should.fail) @@ -112,13 +112,13 @@ describe('AuthorizationCodeGrantType integration', function() { it('should throw an error if `client` is missing', function() { - var model = { + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, expiresAt: new Date(new Date() * 2), user: {} }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); try { grantType.handle(request, null); @@ -130,16 +130,16 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { + const client = { id: 'foobar' }; + const token = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, revokeAuthorizationCode: function() { return true; }, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.handle(request, client) .then(function(data) { @@ -149,40 +149,40 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 'foobar' }; - var model = { + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return Promise.resolve({ authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }); }, revokeAuthorizationCode: function() { return true; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var client = { id: 'foobar' }; - var model = { + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, revokeAuthorizationCode: function() { return true; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var client = { id: 'foobar' }; - var model = { + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function(code, callback) { callback(null, { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }); }, revokeAuthorizationCode: function(code, callback) { callback(null, { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() / 2), user: {} }); }, saveToken: function(tokenToSave, client, user, callback) { callback(null, tokenToSave); } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); @@ -190,14 +190,14 @@ describe('AuthorizationCodeGrantType integration', function() { describe('getAuthorizationCode()', function() { it('should throw an error if the request body does not contain `code`', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { grantType.getAuthorizationCode(request, client); @@ -210,14 +210,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `code` is invalid', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { grantType.getAuthorizationCode(request, client); @@ -230,14 +230,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `authorizationCode` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -248,14 +248,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `authorizationCode.client` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345 }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -266,14 +266,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `authorizationCode.expiresAt` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: {}, user: {} }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -284,14 +284,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `authorizationCode.user` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: {}, expiresAt: new Date() }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -302,16 +302,16 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if the client id does not match', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, expiresAt: new Date(), client: { id: 456 }, user: {} }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -322,17 +322,17 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if the auth code is expired', function() { - var client = { id: 123 }; - var date = new Date(new Date() / 2); - var model = { + const client = { id: 123 }; + const date = new Date(new Date() / 2); + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 123 }, expiresAt: date, user: {} }; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -343,15 +343,15 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if the `redirectUri` is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), redirectUri: 'foobar', user: {} }; - var client = { id: 'foobar' }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), redirectUri: 'foobar', user: {} }; + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return authorizationCode; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(should.fail) @@ -362,15 +362,15 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should return an auth code', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return authorizationCode; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getAuthorizationCode(request, client) .then(function(data) { @@ -380,43 +380,43 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should support promises', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return Promise.resolve(authorizationCode); }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function() { return authorizationCode; }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; - var client = { id: 'foobar' }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + const client = { id: 'foobar' }; + const model = { getAuthorizationCode: function(code, callback) { callback(null, authorizationCode); }, revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); }); @@ -424,14 +424,14 @@ describe('AuthorizationCodeGrantType integration', function() { describe('validateRedirectUri()', function() { it('should throw an error if `redirectUri` is missing', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return authorizationCode; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); try { grantType.validateRedirectUri(request, authorizationCode); @@ -444,14 +444,14 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error if `redirectUri` is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return true; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { code: 12345, redirect_uri: 'http://bar.foo' }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { code: 12345, redirect_uri: 'http://bar.foo' }, headers: {}, method: {}, query: {} }); try { grantType.validateRedirectUri(request, authorizationCode); @@ -466,13 +466,13 @@ describe('AuthorizationCodeGrantType integration', function() { describe('revokeAuthorizationCode()', function() { it('should revoke the auth code', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return true; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); return grantType.revokeAuthorizationCode(authorizationCode) .then(function(data) { @@ -482,13 +482,13 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should throw an error when the auth code is invalid', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return false; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); return grantType.revokeAuthorizationCode(authorizationCode) .then(function(data) { @@ -501,37 +501,37 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should support promises', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return Promise.resolve(true); }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() { return authorizationCode; }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function(code, callback) { callback(null, authorizationCode); }, saveToken: function() {} }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); }); @@ -539,14 +539,14 @@ describe('AuthorizationCodeGrantType integration', function() { describe('saveToken()', function() { it('should save the token', function() { - var token = {}; - var model = { + const token = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); return grantType.saveToken(token) .then(function(data) { @@ -556,37 +556,37 @@ describe('AuthorizationCodeGrantType integration', function() { }); it('should support promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() { return Promise.resolve(token); } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function() { return token; } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var token = {}; - var model = { + const token = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } }; - var grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/client-credentials-grant-type_test.js b/test/integration/grant-types/client-credentials-grant-type_test.js index 3bddec8..b13df08 100644 --- a/test/integration/grant-types/client-credentials-grant-type_test.js +++ b/test/integration/grant-types/client-credentials-grant-type_test.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('chai').should(); +const ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const should = require('chai').should(); /** * Test `ClientCredentialsGrantType` integration. @@ -41,7 +41,7 @@ describe('ClientCredentialsGrantType integration', function() { it('should throw an error if the model does not implement `saveToken()`', function() { try { - var model = { + const model = { getUserFromClient: function() {} }; @@ -57,11 +57,11 @@ describe('ClientCredentialsGrantType integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getUserFromClient: function() {}, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); try { grantType.handle(); @@ -74,12 +74,12 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should throw an error if `client` is missing', function() { - var model = { + const model = { getUserFromClient: function() {}, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { grantType.handle(request); @@ -92,14 +92,14 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should return a token', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); return grantType.handle(request, {}) .then(function(data) { @@ -109,25 +109,25 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should support promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() { return {}; }, saveToken: function() { return token; } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.handle(request, {}).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() { return {}; }, saveToken: function() { return token; } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.handle(request, {}).should.be.an.instanceOf(Promise); }); @@ -135,12 +135,12 @@ describe('ClientCredentialsGrantType integration', function() { describe('getUserFromClient()', function() { it('should throw an error if `user` is missing', function() { - var model = { + const model = { getUserFromClient: function() {}, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); return grantType.getUserFromClient(request, {}) .then(should.fail) @@ -151,13 +151,13 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should return a user', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUserFromClient: function() { return user; }, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); return grantType.getUserFromClient(request, {}) .then(function(data) { @@ -167,37 +167,37 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should support promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUserFromClient: function() { return Promise.resolve(user); }, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUserFromClient: function() {return user; }, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUserFromClient: function(userId, callback) { callback(null, user); }, saveToken: function() {} }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); }); @@ -205,13 +205,13 @@ describe('ClientCredentialsGrantType integration', function() { describe('saveToken()', function() { it('should save the token', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() {}, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); return grantType.saveToken(token) .then(function(data) { @@ -221,34 +221,34 @@ describe('ClientCredentialsGrantType integration', function() { }); it('should support promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() {}, saveToken: function() { return Promise.resolve(token); } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() {}, saveToken: function() { return token; } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUserFromClient: function() {}, saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } }; - var grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/password-grant-type_test.js b/test/integration/grant-types/password-grant-type_test.js index 916355d..a8c4cda 100644 --- a/test/integration/grant-types/password-grant-type_test.js +++ b/test/integration/grant-types/password-grant-type_test.js @@ -4,13 +4,13 @@ * Module dependencies. */ -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var should = require('chai').should(); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const should = require('chai').should(); /** * Test `PasswordGrantType` integration. @@ -42,7 +42,7 @@ describe('PasswordGrantType integration', function() { it('should throw an error if the model does not implement `saveToken()`', function() { try { - var model = { + const model = { getUser: function() {} }; @@ -58,11 +58,11 @@ describe('PasswordGrantType integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); try { grantType.handle(); @@ -75,11 +75,11 @@ describe('PasswordGrantType integration', function() { }); it('should throw an error if `client` is missing', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); try { grantType.handle({}); @@ -92,15 +92,15 @@ describe('PasswordGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { + const client = { id: 'foobar' }; + const token = {}; + const model = { getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'baz'; } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar', scope: 'baz' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar', scope: 'baz' }, headers: {}, method: {}, query: {} }); return grantType.handle(request, client) .then(function(data) { @@ -110,40 +110,40 @@ describe('PasswordGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { + const client = { id: 'foobar' }; + const token = {}; + const model = { getUser: function() { return {}; }, saveToken: function() { return Promise.resolve(token); } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { + const client = { id: 'foobar' }; + const token = {}; + const model = { getUser: function() { return {}; }, saveToken: function() { return token; } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var client = { id: 'foobar' }; - var token = {}; - var model = { + const client = { id: 'foobar' }; + const token = {}; + const model = { getUser: function(username, password, callback) { callback(null, {}); }, saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); @@ -151,12 +151,12 @@ describe('PasswordGrantType integration', function() { describe('getUser()', function() { it('should throw an error if the request body does not contain `username`', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { grantType.getUser(request); @@ -169,12 +169,12 @@ describe('PasswordGrantType integration', function() { }); it('should throw an error if the request body does not contain `password`', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo' }, headers: {}, method: {}, query: {} }); try { grantType.getUser(request); @@ -187,12 +187,12 @@ describe('PasswordGrantType integration', function() { }); it('should throw an error if `username` is invalid', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, method: {}, query: {} }); try { grantType.getUser(request); @@ -205,12 +205,12 @@ describe('PasswordGrantType integration', function() { }); it('should throw an error if `password` is invalid', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, method: {}, query: {} }); try { grantType.getUser(request); @@ -223,12 +223,12 @@ describe('PasswordGrantType integration', function() { }); it('should throw an error if `user` is missing', function() { - var model = { + const model = { getUser: function() {}, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); return grantType.getUser(request) .then(should.fail) @@ -239,13 +239,13 @@ describe('PasswordGrantType integration', function() { }); it('should return a user', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUser: function() { return user; }, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); return grantType.getUser(request) .then(function(data) { @@ -255,37 +255,37 @@ describe('PasswordGrantType integration', function() { }); it('should support promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUser: function() { return Promise.resolve(user); }, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.getUser(request).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUser: function() { return user; }, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.getUser(request).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var user = { email: 'foo@bar.com' }; - var model = { + const user = { email: 'foo@bar.com' }; + const model = { getUser: function(username, password, callback) { callback(null, user); }, saveToken: function() {} }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); grantType.getUser(request).should.be.an.instanceOf(Promise); }); @@ -293,13 +293,13 @@ describe('PasswordGrantType integration', function() { describe('saveToken()', function() { it('should save the token', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUser: function() {}, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); return grantType.saveToken(token) .then(function(data) { @@ -309,34 +309,34 @@ describe('PasswordGrantType integration', function() { }); it('should support promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUser: function() {}, saveToken: function() { return Promise.resolve(token); } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUser: function() {}, saveToken: function() { return token; } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var token = {}; - var model = { + const token = {}; + const model = { getUser: function() {}, saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } }; - var grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/refresh-token-grant-type_test.js b/test/integration/grant-types/refresh-token-grant-type_test.js index cbc2947..945d51c 100644 --- a/test/integration/grant-types/refresh-token-grant-type_test.js +++ b/test/integration/grant-types/refresh-token-grant-type_test.js @@ -4,14 +4,14 @@ * Module dependencies. */ -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var Promise = require('bluebird'); -var RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); -var Request = require('../../../lib/request'); -var ServerError = require('../../../lib/errors/server-error'); -var should = require('chai').should(); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const Promise = require('bluebird'); +const RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); +const Request = require('../../../lib/request'); +const ServerError = require('../../../lib/errors/server-error'); +const should = require('chai').should(); /** * Test `RefreshTokenGrantType` integration. @@ -43,7 +43,7 @@ describe('RefreshTokenGrantType integration', function() { it('should throw an error if the model does not implement `revokeToken()`', function() { try { - var model = { + const model = { getRefreshToken: function() {} }; @@ -58,7 +58,7 @@ describe('RefreshTokenGrantType integration', function() { it('should throw an error if the model does not implement `saveToken()`', function() { try { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: function() {} }; @@ -75,12 +75,12 @@ describe('RefreshTokenGrantType integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); try { grantType.handle(); @@ -93,13 +93,13 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `client` is missing', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { grantType.handle(request); @@ -112,15 +112,15 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { getRefreshToken: function() { return token; }, revokeToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, saveToken: function() { return token; } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); return grantType.handle(request, client) .then(function(data) { @@ -130,40 +130,40 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function() { return Promise.resolve({ accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function() { return Promise.resolve({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, saveToken: function() { return Promise.resolve({ accessToken: 'foo', client: {}, user: {} }); } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, user: {} }; }, revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, saveToken: function() { return { accessToken: 'foo', client: {}, user: {} }; } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: { id: 123 }, user: {} }); }, revokeToken: function(refreshToken, callback) { callback(null, { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }); }, saveToken: function(tokenToSave, client, user, callback) { callback(null,{ accessToken: 'foo', client: {}, user: {} }); } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); @@ -171,14 +171,14 @@ describe('RefreshTokenGrantType integration', function() { describe('getRefreshToken()', function() { it('should throw an error if the `refreshToken` parameter is missing from the request body', function() { - var client = {}; - var model = { + const client = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { grantType.getRefreshToken(request, client); @@ -191,14 +191,14 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshToken` is not found', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function() { return; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: '12345' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: '12345' }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -209,14 +209,14 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshToken.client` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getRefreshToken: function() { return {}; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -227,16 +227,16 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshToken.user` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -247,16 +247,16 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if the client id does not match', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 456 }, user: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -267,16 +267,16 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refresh_token` contains invalid characters', function() { - var client = {}; - var model = { + const client = {}; + const model = { getRefreshToken: function() { return { client: { id: 456 }, user: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { grantType.getRefreshToken(request, client); @@ -289,16 +289,16 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refresh_token` is missing', function() { - var client = {}; - var model = { + const client = {}; + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 456 }, user: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -309,17 +309,17 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refresh_token` is expired', function() { - var client = { id: 123 }; - var date = new Date(new Date() / 2); - var model = { + const client = { id: 123 }; + const date = new Date(new Date() / 2); + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: date, user: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -330,16 +330,16 @@ describe('RefreshTokenGrantType integration', function() { }); it('should throw an error if `refreshTokenExpiresAt` is not a date value', function() { - var client = { id: 123 }; - var model = { + const client = { id: 123 }; + const model = { getRefreshToken: function() { return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: 'stringvalue', user: {} }; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(should.fail) @@ -350,15 +350,15 @@ describe('RefreshTokenGrantType integration', function() { }); it('should return a token', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { getRefreshToken: function() { return token; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); return grantType.getRefreshToken(request, client) .then(function(data) { @@ -368,43 +368,43 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { getRefreshToken: function() { return Promise.resolve(token); }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { getRefreshToken: function() { return token; }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var client = { id: 123 }; - var token = { accessToken: 'foo', client: { id: 123 }, user: {} }; - var model = { + const client = { id: 123 }; + const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; + const model = { getRefreshToken: function(refreshToken, callback) { callback(null, token); }, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); - var request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); }); @@ -412,12 +412,12 @@ describe('RefreshTokenGrantType integration', function() { describe('revokeToken()', function() { it('should throw an error if the `token` is invalid', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); grantType.revokeToken({}) .then(should.fail) @@ -428,13 +428,13 @@ describe('RefreshTokenGrantType integration', function() { }); it('should revoke the token', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + const model = { getRefreshToken: function() {}, revokeToken: function() { return token; }, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); return grantType.revokeToken(token) .then(function(data) { @@ -444,37 +444,37 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + const model = { getRefreshToken: function() {}, revokeToken: function() { return Promise.resolve(token); }, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeToken(token).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + const model = { getRefreshToken: function() {}, revokeToken: function() { return token; }, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeToken(token).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + const model = { getRefreshToken: function() {}, revokeToken: function(refreshToken, callback) { callback(null, token); }, saveToken: function() {} }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.revokeToken(token).should.be.an.instanceOf(Promise); }); @@ -482,13 +482,13 @@ describe('RefreshTokenGrantType integration', function() { describe('saveToken()', function() { it('should save the token', function() { - var token = {}; - var model = { + const token = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() { return token; } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); return grantType.saveToken(token) .then(function(data) { @@ -498,37 +498,37 @@ describe('RefreshTokenGrantType integration', function() { }); it('should support promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() { return Promise.resolve(token); } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var token = {}; - var model = { + const token = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function() { return token; } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var token = {}; - var model = { + const token = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: function(tokenToSave, client, user, callback) { callback(null, token); } }; - var grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js index 1e98a62..3e0eefd 100644 --- a/test/integration/handlers/authenticate-handler_test.js +++ b/test/integration/handlers/authenticate-handler_test.js @@ -4,18 +4,18 @@ * Module dependencies. */ -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var InsufficientScopeError = require('../../../lib/errors/insufficient-scope-error'); -var InvalidTokenError = require('../../../lib/errors/invalid-token-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var UnauthorizedRequestError = require('../../../lib/errors/unauthorized-request-error'); -var should = require('chai').should(); +const AccessDeniedError = require('../../../lib/errors/access-denied-error'); +const AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const InsufficientScopeError = require('../../../lib/errors/insufficient-scope-error'); +const InvalidTokenError = require('../../../lib/errors/invalid-token-error'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const Response = require('../../../lib/response'); +const ServerError = require('../../../lib/errors/server-error'); +const UnauthorizedRequestError = require('../../../lib/errors/unauthorized-request-error'); +const should = require('chai').should(); /** * Test `AuthenticateHandler` integration. @@ -79,18 +79,18 @@ describe('AuthenticateHandler integration', function() { }); it('should set the `model`', function() { - var model = { getAccessToken: function() {} }; - var grantType = new AuthenticateHandler({ model: model }); + const model = { getAccessToken: function() {} }; + const grantType = new AuthenticateHandler({ model: model }); grantType.model.should.equal(model); }); it('should set the `scope`', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var grantType = new AuthenticateHandler({ + const grantType = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, @@ -103,7 +103,7 @@ describe('AuthenticateHandler integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); try { handler.handle(); @@ -116,14 +116,14 @@ describe('AuthenticateHandler integration', function() { }); it('should set the `WWW-Authenticate` header if an unauthorized request error is thrown', function() { - var model = { + const model = { getAccessToken: function() { throw new UnauthorizedRequestError(); } }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -133,14 +133,14 @@ describe('AuthenticateHandler integration', function() { }); it('should throw the error if an oauth error is thrown', function() { - var model = { + const model = { getAccessToken: function() { throw new AccessDeniedError('Cannot request this access token'); } }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -151,14 +151,14 @@ describe('AuthenticateHandler integration', function() { }); it('should throw a server error if a non-oauth error is thrown', function() { - var model = { + const model = { getAccessToken: function() { throw new Error('Unhandled exception'); } }; - var handler = new AuthenticateHandler({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -169,11 +169,11 @@ describe('AuthenticateHandler integration', function() { }); it('should return an access token', function() { - var accessToken = { + const accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; - var model = { + const model = { getAccessToken: function() { return accessToken; }, @@ -181,14 +181,14 @@ describe('AuthenticateHandler integration', function() { return true; } }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); - var request = new Request({ + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function(data) { @@ -200,8 +200,8 @@ describe('AuthenticateHandler integration', function() { describe('getTokenFromRequest()', function() { it('should throw an error if more than one authentication method is used', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, @@ -219,8 +219,8 @@ describe('AuthenticateHandler integration', function() { }); it('should throw an error if `accessToken` is missing', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.getTokenFromRequest(request); @@ -235,8 +235,8 @@ describe('AuthenticateHandler integration', function() { describe('getTokenFromRequestHeader()', function() { it('should throw an error if the token is malformed', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: { 'Authorization': 'foobar' @@ -256,8 +256,8 @@ describe('AuthenticateHandler integration', function() { }); it('should return the bearer token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' @@ -266,7 +266,7 @@ describe('AuthenticateHandler integration', function() { query: {} }); - var bearerToken = handler.getTokenFromRequestHeader(request); + const bearerToken = handler.getTokenFromRequestHeader(request); bearerToken.should.equal('foo'); }); @@ -274,7 +274,7 @@ describe('AuthenticateHandler integration', function() { describe('getTokenFromRequestQuery()', function() { it('should throw an error if the query contains a token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); try { handler.getTokenFromRequestQuery(); @@ -287,7 +287,7 @@ describe('AuthenticateHandler integration', function() { }); it('should return the bearer token if `allowBearerTokensInQueryString` is true', function() { - var handler = new AuthenticateHandler({ allowBearerTokensInQueryString: true, model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ allowBearerTokensInQueryString: true, model: { getAccessToken: function() {} } }); handler.getTokenFromRequestQuery({ query: { access_token: 'foo' } }).should.equal('foo'); }); @@ -295,8 +295,8 @@ describe('AuthenticateHandler integration', function() { describe('getTokenFromRequestBody()', function() { it('should throw an error if the method is `GET`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: { access_token: 'foo' }, headers: {}, method: 'GET', @@ -314,8 +314,8 @@ describe('AuthenticateHandler integration', function() { }); it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: { access_token: 'foo' }, headers: {}, method: {}, @@ -333,8 +333,8 @@ describe('AuthenticateHandler integration', function() { }); it('should return the bearer token', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: { access_token: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: {}, @@ -347,10 +347,10 @@ describe('AuthenticateHandler integration', function() { describe('getAccessToken()', function() { it('should throw an error if `accessToken` is missing', function() { - var model = { + const model = { getAccessToken: function() {} }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); return handler.getAccessToken('foo') .then(should.fail) @@ -361,12 +361,12 @@ describe('AuthenticateHandler integration', function() { }); it('should throw an error if `accessToken.user` is missing', function() { - var model = { + const model = { getAccessToken: function() { return {}; } }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); return handler.getAccessToken('foo') .then(should.fail) @@ -377,13 +377,13 @@ describe('AuthenticateHandler integration', function() { }); it('should return an access token', function() { - var accessToken = { user: {} }; - var model = { + const accessToken = { user: {} }; + const model = { getAccessToken: function() { return accessToken; } }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); return handler.getAccessToken('foo') .then(function(data) { @@ -393,34 +393,34 @@ describe('AuthenticateHandler integration', function() { }); it('should support promises', function() { - var model = { + const model = { getAccessToken: function() { return Promise.resolve({ user: {} }); } }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); handler.getAccessToken('foo').should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { getAccessToken: function() { return { user: {} }; } }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); handler.getAccessToken('foo').should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var model = { + const model = { getAccessToken: function(token, callback) { callback(null, { user: {} }); } }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); handler.getAccessToken('foo').should.be.an.instanceOf(Promise); }); @@ -428,8 +428,8 @@ describe('AuthenticateHandler integration', function() { describe('validateAccessToken()', function() { it('should throw an error if `accessToken` is expired', function() { - var accessToken = { accessTokenExpiresAt: new Date(new Date() / 2) }; - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const accessToken = { accessTokenExpiresAt: new Date(new Date() / 2) }; + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); try { handler.validateAccessToken(accessToken); @@ -442,11 +442,11 @@ describe('AuthenticateHandler integration', function() { }); it('should return an access token', function() { - var accessToken = { + const accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); handler.validateAccessToken(accessToken).should.equal(accessToken); }); @@ -454,13 +454,13 @@ describe('AuthenticateHandler integration', function() { describe('verifyScope()', function() { it('should throw an error if `scope` is insufficient', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() { return false; } }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); return handler.verifyScope('foo') .then(should.fail) @@ -471,37 +471,37 @@ describe('AuthenticateHandler integration', function() { }); it('should support promises', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() { return true; } }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); handler.verifyScope('foo').should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() { return true; } }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); handler.verifyScope('foo').should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function(token, scope, callback) { callback(null, true); } }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); handler.verifyScope('foo').should.be.an.instanceOf(Promise); }); @@ -509,12 +509,12 @@ describe('AuthenticateHandler integration', function() { describe('updateResponse()', function() { it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model }); + const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: 'foo biz' }); @@ -522,12 +522,12 @@ describe('AuthenticateHandler integration', function() { }); it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: 'foo bar' }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: 'foo bar' }); + const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: 'foo biz' }); @@ -535,12 +535,12 @@ describe('AuthenticateHandler integration', function() { }); it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model }); + const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: 'foo biz' }); @@ -548,12 +548,12 @@ describe('AuthenticateHandler integration', function() { }); it('should set the `X-Authorized-OAuth-Scopes` header', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: 'foo bar' }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: 'foo bar' }); + const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: 'foo biz' }); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index afe737e..efcdf76 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -4,22 +4,22 @@ * Module dependencies. */ -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); -var CodeResponseType = require('../../../lib/response-types/code-response-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidClientError = require('../../../lib/errors/invalid-client-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var InvalidScopeError = require('../../../lib/errors/invalid-scope-error'); -var UnsupportedResponseTypeError = require('../../../lib/errors/unsupported-response-type-error'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); -var should = require('chai').should(); -var url = require('url'); +const AccessDeniedError = require('../../../lib/errors/access-denied-error'); +const AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); +const AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); +const CodeResponseType = require('../../../lib/response-types/code-response-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidClientError = require('../../../lib/errors/invalid-client-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const InvalidScopeError = require('../../../lib/errors/invalid-scope-error'); +const UnsupportedResponseTypeError = require('../../../lib/errors/unsupported-response-type-error'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const Response = require('../../../lib/response'); +const ServerError = require('../../../lib/errors/server-error'); +const UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); +const should = require('chai').should(); +const url = require('url'); /** * Test `AuthorizeHandler` integration. @@ -72,7 +72,7 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if the model does not implement `getAccessToken()`', function() { - var model = { + const model = { getClient: function() {}, saveAuthorizationCode: function() {} }; @@ -88,34 +88,34 @@ describe('AuthorizeHandler integration', function() { }); it('should set the `authorizationCodeLifetime`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.authorizationCodeLifetime.should.equal(120); }); it('should set the `authenticateHandler`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.authenticateHandler.should.be.an.instanceOf(AuthenticateHandler); }); it('should set the `model`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.model.should.equal(model); }); @@ -123,12 +123,12 @@ describe('AuthorizeHandler integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); try { handler.handle(); @@ -141,13 +141,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `response` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.handle(request); @@ -160,14 +160,35 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `allowed` is `false`', function() { - var model = { - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + const model = { + getAccessToken: function() { + return { + user: {}, + accessTokenExpiresAt: new Date(new Date().getTime() + 10000) + }; + }, + getClient: function() { + return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + }, + saveAuthorizationCode: function() { + throw new Error('Unhandled exception'); + } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { allowed: 'false' } }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ + body: { + client_id: 'test' + }, + headers: { + 'Authorization': 'Bearer foo' + }, + method: {}, + query: { + allowed: 'false', + state: 'foobar' + } + }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -178,7 +199,7 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to an error response if a non-oauth error is thrown', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -192,8 +213,8 @@ describe('AuthorizeHandler integration', function() { throw new Error('Unhandled exception'); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -206,7 +227,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -216,7 +237,7 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to an error response if an oauth error is thrown', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -230,8 +251,8 @@ describe('AuthorizeHandler integration', function() { throw new AccessDeniedError('Cannot request this auth code'); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -244,7 +265,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -254,8 +275,8 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to a successful response with `code` and `state` if successful', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const model = { getAccessToken: function() { return { client: client, @@ -270,8 +291,8 @@ describe('AuthorizeHandler integration', function() { return { authorizationCode: 12345, client: client }; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -284,7 +305,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function() { @@ -294,7 +315,7 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to an error response if `scope` is invalid', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -308,8 +329,8 @@ describe('AuthorizeHandler integration', function() { return {}; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -323,18 +344,18 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) .catch(function() { - response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60'); + response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60&state=foobar'); }); }); it('should redirect to a successful response if `model.validateScope` is not defined', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const model = { getAccessToken: function() { return { client: client, @@ -349,8 +370,8 @@ describe('AuthorizeHandler integration', function() { return { authorizationCode: 12345, client: client }; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -364,7 +385,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function(data) { @@ -377,8 +398,8 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to an error response if `scope` is insufficient', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const model = { getAccessToken: function() { return { client: client, @@ -396,8 +417,8 @@ describe('AuthorizeHandler integration', function() { return false; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -411,17 +432,17 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) .catch(function() { - response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid'); + response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid&state=foobar'); }); }); it('should redirect to an error response if `state` is missing', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -435,8 +456,8 @@ describe('AuthorizeHandler integration', function() { throw new AccessDeniedError('Cannot request this auth code'); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -447,7 +468,7 @@ describe('AuthorizeHandler integration', function() { method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -457,7 +478,7 @@ describe('AuthorizeHandler integration', function() { }); it('should redirect to an error response if `response_type` is invalid', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -471,8 +492,8 @@ describe('AuthorizeHandler integration', function() { return { authorizationCode: 12345, client: {} }; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'test' @@ -485,7 +506,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -495,7 +516,7 @@ describe('AuthorizeHandler integration', function() { }); it('should fail on invalid `response_type` before calling model.saveAuthorizationCode()', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -509,8 +530,8 @@ describe('AuthorizeHandler integration', function() { throw new Error('must not be reached'); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'test' @@ -523,7 +544,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -533,8 +554,8 @@ describe('AuthorizeHandler integration', function() { }); it('should return the `code` if successful', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const model = { getAccessToken: function() { return { client: client, @@ -549,8 +570,8 @@ describe('AuthorizeHandler integration', function() { return { authorizationCode: 12345, client: client }; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' @@ -563,7 +584,7 @@ describe('AuthorizeHandler integration', function() { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function(data) { @@ -578,12 +599,12 @@ describe('AuthorizeHandler integration', function() { describe('generateAuthorizationCode()', function() { it('should return an auth code', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); return handler.generateAuthorizationCode() .then(function(data) { @@ -593,7 +614,7 @@ describe('AuthorizeHandler integration', function() { }); it('should support promises', function() { - var model = { + const model = { generateAuthorizationCode: function() { return Promise.resolve({}); }, @@ -601,13 +622,13 @@ describe('AuthorizeHandler integration', function() { getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { generateAuthorizationCode: function() { return {}; }, @@ -615,7 +636,7 @@ describe('AuthorizeHandler integration', function() { getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); }); @@ -623,26 +644,85 @@ describe('AuthorizeHandler integration', function() { describe('getAuthorizationCodeLifetime()', function() { it('should return a date', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); }); }); + describe('validateRedirectUri()', function() { + it('should support empty method', function() { + const model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + + handler.validateRedirectUri('http://example.com/a', { redirectUris: ['http://example.com/a'] }).should.be.an.instanceOf(Promise); + }); + + it('should support promises', function() { + const model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {}, + validateRedirectUri: function() { + return Promise.resolve(true); + } + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + + handler.validateRedirectUri('http://example.com/a', { }).should.be.an.instanceOf(Promise); + }); + + it('should support non-promises', function() { + const model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {}, + validateRedirectUri: function() { + return true; + } + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + + handler.validateRedirectUri('http://example.com/a', { }).should.be.an.instanceOf(Promise); + }); + + it('should support callbacks', function() { + const model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {}, + validateRedirectUri: function(redirectUri, client, callback) { + callback(null, false); + } + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + + handler.validateRedirectUri('http://example.com/a', { }).should.be.an.instanceOf(Promise); + }); + }); + describe('getClient()', function() { it('should throw an error if `client_id` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); try { handler.getClient(request); @@ -655,13 +735,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client_id` is invalid', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 'øå€£‰', response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 'øå€£‰', response_type: 'code' }, headers: {}, method: {}, query: {} }); try { handler.getClient(request); @@ -674,13 +754,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client.redirectUri` is invalid', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'foobar' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'foobar' }, headers: {}, method: {}, query: {} }); try { handler.getClient(request); @@ -693,13 +773,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -710,15 +790,15 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client.grants` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return {}; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -729,15 +809,15 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client` is unauthorized', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return { grants: [] }; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -748,13 +828,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client.redirectUri` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return { grants: ['authorization_code'] }; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -765,15 +845,15 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return { grants: ['authorization_code'], redirectUris: ['https://example.com'] }; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'https://foobar.com' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'https://foobar.com' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -784,15 +864,15 @@ describe('AuthorizeHandler integration', function() { }); it('should support promises', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return Promise.resolve({ grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }); }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345 }, headers: {}, method: {}, @@ -803,15 +883,15 @@ describe('AuthorizeHandler integration', function() { }); it('should support non-promises', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() { return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345 }, headers: {}, method: {}, @@ -822,7 +902,7 @@ describe('AuthorizeHandler integration', function() { }); it('should support callbacks', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function(clientId, clientSecret, callback) { should.equal(clientSecret, null); @@ -830,8 +910,8 @@ describe('AuthorizeHandler integration', function() { }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345 }, headers: {}, method: {}, @@ -843,16 +923,16 @@ describe('AuthorizeHandler integration', function() { describe('with `client_id` in the request query', function() { it('should return a client', function() { - var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; - var model = { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const model = { getAccessToken: function() {}, getClient: function() { return client; }, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: { client_id: 12345 } }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: { client_id: 12345 } }); return handler.getClient(request) .then(function(data) { @@ -865,13 +945,13 @@ describe('AuthorizeHandler integration', function() { describe('getScope()', function() { it('should throw an error if `scope` is invalid', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { handler.getScope(request); @@ -885,13 +965,13 @@ describe('AuthorizeHandler integration', function() { describe('with `scope` in the request body', function() { it('should return the scope', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); handler.getScope(request).should.equal('foo'); }); @@ -899,13 +979,13 @@ describe('AuthorizeHandler integration', function() { describe('with `scope` in the request query', function() { it('should return the scope', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { scope: 'foo' } }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: { scope: 'foo' } }); handler.getScope(request).should.equal('foo'); }); @@ -914,13 +994,13 @@ describe('AuthorizeHandler integration', function() { describe('getState()', function() { it('should throw an error if `allowEmptyState` is false and `state` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ allowEmptyState: false, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ allowEmptyState: false, authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.getState(request); @@ -932,14 +1012,26 @@ describe('AuthorizeHandler integration', function() { } }); + it('should allow missing `state` if `allowEmptyState` is valid', function () { + const model = { + getAccessToken: function() {}, + getClient: function() {}, + saveAuthorizationCode: function() {} + }; + const handler = new AuthorizeHandler({ allowEmptyState: true, authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const state = handler.getState(request); + should.equal(state, undefined); + }); + it('should throw an error if `state` is invalid', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'øå€£‰' } }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'øå€£‰' } }); try { handler.getState(request); @@ -953,13 +1045,13 @@ describe('AuthorizeHandler integration', function() { describe('with `state` in the request body', function() { it('should return the state', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { state: 'foobar' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { state: 'foobar' }, headers: {}, method: {}, query: {} }); handler.getState(request).should.equal('foobar'); }); @@ -967,13 +1059,13 @@ describe('AuthorizeHandler integration', function() { describe('with `state` in the request query', function() { it('should return the state', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'foobar' } }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'foobar' } }); handler.getState(request).should.equal('foobar'); }); @@ -982,14 +1074,14 @@ describe('AuthorizeHandler integration', function() { describe('getUser()', function() { it('should throw an error if `user` is missing', function() { - var authenticateHandler = { handle: function() {} }; - var model = { + const authenticateHandler = { handle: function() {} }; + const model = { getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - var response = new Response(); + const handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const response = new Response(); return handler.getUser(request, response) .then(should.fail) @@ -1000,8 +1092,8 @@ describe('AuthorizeHandler integration', function() { }); it('should return a user', function() { - var user = {}; - var model = { + const user = {}; + const model = { getAccessToken: function() { return { user: user, @@ -1011,9 +1103,9 @@ describe('AuthorizeHandler integration', function() { getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.getUser(request, response) .then(function(data) { @@ -1025,15 +1117,15 @@ describe('AuthorizeHandler integration', function() { describe('saveAuthorizationCode()', function() { it('should return an auth code', function() { - var authorizationCode = {}; - var model = { + const authorizationCode = {}; + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() { return authorizationCode; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); return handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz') .then(function(data) { @@ -1043,40 +1135,40 @@ describe('AuthorizeHandler integration', function() { }); it('should support promises when calling `model.saveAuthorizationCode()`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() { return Promise.resolve({}); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); }); it('should support non-promises when calling `model.saveAuthorizationCode()`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() { return {}; } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); }); it('should support callbacks when calling `model.saveAuthorizationCode()`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function(code, client, user, callback) { return callback(null, true); } }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); }); @@ -1084,13 +1176,13 @@ describe('AuthorizeHandler integration', function() { describe('getResponseType()', function() { it('should throw an error if `response_type` is missing', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.getResponseType(request); @@ -1103,13 +1195,13 @@ describe('AuthorizeHandler integration', function() { }); it('should throw an error if `response_type` is not `code`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'foobar' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { response_type: 'foobar' }, headers: {}, method: {}, query: {} }); try { handler.getResponseType(request); @@ -1123,14 +1215,14 @@ describe('AuthorizeHandler integration', function() { describe('with `response_type` in the request body', function() { it('should return a response type', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); - var ResponseType = handler.getResponseType(request); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); + const ResponseType = handler.getResponseType(request); ResponseType.should.equal(CodeResponseType); }); @@ -1138,14 +1230,14 @@ describe('AuthorizeHandler integration', function() { describe('with `response_type` in the request query', function() { it('should return a response type', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: { response_type: 'code' } }); - var ResponseType = handler.getResponseType(request); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: { response_type: 'code' } }); + const ResponseType = handler.getResponseType(request); ResponseType.should.equal(CodeResponseType); }); @@ -1154,14 +1246,14 @@ describe('AuthorizeHandler integration', function() { describe('buildSuccessRedirectUri()', function() { it('should return a redirect uri', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var responseType = new CodeResponseType(12345); - var redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const responseType = new CodeResponseType(12345); + const redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); url.format(redirectUri).should.equal('http://example.com/cb?code=12345'); }); @@ -1169,27 +1261,27 @@ describe('AuthorizeHandler integration', function() { describe('buildErrorRedirectUri()', function() { it('should set `error_description` if available', function() { - var error = new InvalidClientError('foo bar'); - var model = { + const error = new InvalidClientError('foo bar'); + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=foo%20bar'); }); it('should return a redirect uri', function() { - var error = new InvalidClientError(); - var model = { + const error = new InvalidClientError(); + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=Bad%20Request'); }); @@ -1197,14 +1289,14 @@ describe('AuthorizeHandler integration', function() { describe('updateResponse()', function() { it('should set the `location` header', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var response = new Response({ body: {}, headers: {} }); - var uri = url.parse('http://example.com/cb'); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const response = new Response({ body: {}, headers: {} }); + const uri = url.parse('http://example.com/cb'); handler.updateResponse(response, uri, 'foobar'); diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 19b69b5..41ec524 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -4,22 +4,22 @@ * Module dependencies. */ -var AccessDeniedError = require('../../../lib/errors/access-denied-error'); -var BearerTokenType = require('../../../lib/token-types/bearer-token-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var InvalidClientError = require('../../../lib/errors/invalid-client-error'); -var InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); -var InvalidRequestError = require('../../../lib/errors/invalid-request-error'); -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var ServerError = require('../../../lib/errors/server-error'); -var TokenHandler = require('../../../lib/handlers/token-handler'); -var UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); -var UnsupportedGrantTypeError = require('../../../lib/errors/unsupported-grant-type-error'); -var should = require('chai').should(); -var util = require('util'); +const AccessDeniedError = require('../../../lib/errors/access-denied-error'); +const BearerTokenType = require('../../../lib/token-types/bearer-token-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const InvalidClientError = require('../../../lib/errors/invalid-client-error'); +const InvalidGrantError = require('../../../lib/errors/invalid-grant-error'); +const InvalidRequestError = require('../../../lib/errors/invalid-request-error'); +const PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const Response = require('../../../lib/response'); +const ServerError = require('../../../lib/errors/server-error'); +const TokenHandler = require('../../../lib/handlers/token-handler'); +const UnauthorizedClientError = require('../../../lib/errors/unauthorized-client-error'); +const UnsupportedGrantTypeError = require('../../../lib/errors/unsupported-grant-type-error'); +const should = require('chai').should(); +const util = require('util'); /** * Test `TokenHandler` integration. @@ -72,75 +72,75 @@ describe('TokenHandler integration', function() { }); it('should set the `accessTokenLifetime`', function() { - var accessTokenLifetime = {}; - var model = { + const accessTokenLifetime = {}; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: accessTokenLifetime, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: accessTokenLifetime, model: model, refreshTokenLifetime: 120 }); handler.accessTokenLifetime.should.equal(accessTokenLifetime); }); it('should set the `alwaysIssueNewRefreshToken`', function() { - var alwaysIssueNewRefreshToken = true; - var model = { + const alwaysIssueNewRefreshToken = true; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); + const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); }); it('should set the `alwaysIssueNewRefreshToken` to false', function() { - var alwaysIssueNewRefreshToken = false; - var model = { + const alwaysIssueNewRefreshToken = false; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); + const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); }); it('should return the default `alwaysIssueNewRefreshToken` value', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120 }); handler.alwaysIssueNewRefreshToken.should.equal(true); }); it('should set the `extendedGrantTypes`', function() { - var extendedGrantTypes = { foo: 'bar' }; - var model = { + const extendedGrantTypes = { foo: 'bar' }; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, extendedGrantTypes: extendedGrantTypes, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, extendedGrantTypes: extendedGrantTypes, model: model, refreshTokenLifetime: 120 }); handler.grantTypes.should.deep.include(extendedGrantTypes); }); it('should set the `model`', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.model.should.equal(model); }); it('should set the `refreshTokenLifetime`', function() { - var refreshTokenLifetime = {}; - var model = { + const refreshTokenLifetime = {}; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: refreshTokenLifetime }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: refreshTokenLifetime }); handler.refreshTokenLifetime.should.equal(refreshTokenLifetime); }); @@ -148,11 +148,11 @@ describe('TokenHandler integration', function() { describe('handle()', function() { it('should throw an error if `request` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); try { handler.handle(); @@ -165,12 +165,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `response` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.handle(request); @@ -183,13 +183,13 @@ describe('TokenHandler integration', function() { }); it('should throw an error if the method is not `POST`', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: {}, method: 'GET', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: {}, method: 'GET', query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -200,13 +200,13 @@ describe('TokenHandler integration', function() { }); it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: {}, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: {}, method: 'POST', query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -217,13 +217,13 @@ describe('TokenHandler integration', function() { }); it('should throw the error if an oauth error is thrown', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -234,15 +234,15 @@ describe('TokenHandler integration', function() { }); it('should throw a server error if a non-oauth error is thrown', function() { - var model = { + const model = { getClient: function() { throw new Error('Unhandled exception'); }, getUser: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -254,7 +254,7 @@ describe('TokenHandler integration', function() { method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -266,15 +266,15 @@ describe('TokenHandler integration', function() { }); it('should update the response if an error is thrown', function() { - var model = { + const model = { getClient: function() { throw new Error('Unhandled exception'); }, getUser: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -286,7 +286,7 @@ describe('TokenHandler integration', function() { method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(should.fail) @@ -297,15 +297,15 @@ describe('TokenHandler integration', function() { }); it('should return a bearer token if successful', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {} }; + const model = { getClient: function() { return { grants: ['password'] }; }, getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'baz'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -318,7 +318,7 @@ describe('TokenHandler integration', function() { method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function(data) { @@ -328,15 +328,15 @@ describe('TokenHandler integration', function() { }); it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; + const model = { getClient: function() { return { grants: ['password'] }; }, getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'baz'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -349,7 +349,7 @@ describe('TokenHandler integration', function() { method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function() { @@ -363,15 +363,15 @@ describe('TokenHandler integration', function() { }); it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', function() { - var token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; - var model = { + const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: 'foobar', user: {}, foo: 'bar' }; + const model = { getClient: function() { return { grants: ['password'] }; }, getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'baz'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, allowExtendedTokenAttributes: true }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, allowExtendedTokenAttributes: true }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -384,7 +384,7 @@ describe('TokenHandler integration', function() { method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.handle(request, response) .then(function() { @@ -401,12 +401,12 @@ describe('TokenHandler integration', function() { describe('getClient()', function() { it('should throw an error if `clientId` is invalid', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, method: {}, query: {} }); try { handler.getClient(request); @@ -419,12 +419,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `clientSecret` is invalid', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { handler.getClient(request); @@ -437,12 +437,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `client` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -453,12 +453,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `client.grants` is missing', function() { - var model = { + const model = { getClient: function() { return {}; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -469,12 +469,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `client.grants` is invalid', function() { - var model = { + const model = { getClient: function() { return { grants: 'foobar' }; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(should.fail) @@ -485,18 +485,18 @@ describe('TokenHandler integration', function() { }); it('should throw a 401 error if the client is invalid and the request contains an authorization header', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: { 'authorization': util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); return handler.getClient(request, response) .then(should.fail) @@ -510,13 +510,13 @@ describe('TokenHandler integration', function() { }); it('should return a client', function() { - var client = { id: 12345, grants: [] }; - var model = { + const client = { id: 12345, grants: [] }; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(function(data) { @@ -528,13 +528,13 @@ describe('TokenHandler integration', function() { describe('with `password` grant type and `requireClientAuthentication` is false', function() { it('should return a client ', function() { - var client = { id: 12345, grants: [] }; - var model = { + const client = { id: 12345, grants: [] }; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, @@ -542,7 +542,7 @@ describe('TokenHandler integration', function() { password: false } }); - var request = new Request({ body: { client_id: 'blah', grant_type: 'password'}, headers: {}, method: {}, query: {} }); + const request = new Request({ body: { client_id: 'blah', grant_type: 'password'}, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(function(data) { @@ -555,13 +555,13 @@ describe('TokenHandler integration', function() { describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', function() { it('should return a client ', function() { - var client = { id: 12345, grants: [] }; - var model = { + const client = { id: 12345, grants: [] }; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, @@ -569,7 +569,7 @@ describe('TokenHandler integration', function() { password: false } }); - var request = new Request({ + const request = new Request({ body: { grant_type: 'password'}, headers: { 'authorization': util.format('Basic %s', Buffer.from('blah:').toString('base64')) }, method: {}, @@ -585,34 +585,34 @@ describe('TokenHandler integration', function() { }); it('should support promises', function() { - var model = { + const model = { getClient: function() { return Promise.resolve({ grants: [] }); }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); handler.getClient(request).should.be.an.instanceOf(Promise); }); it('should support non-promises', function() { - var model = { + const model = { getClient: function() { return { grants: [] }; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); handler.getClient(request).should.be.an.instanceOf(Promise); }); it('should support callbacks', function() { - var model = { + const model = { getClient: function(clientId, clientSecret, callback) { callback(null, { grants: [] }); }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); handler.getClient(request).should.be.an.instanceOf(Promise); }); @@ -620,12 +620,12 @@ describe('TokenHandler integration', function() { describe('getClientCredentials()', function() { it('should throw an error if `client_id` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_secret: 'foo' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_secret: 'foo' }, headers: {}, method: {}, query: {} }); try { handler.getClientCredentials(request); @@ -638,12 +638,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `client_secret` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 'foo' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 'foo' }, headers: {}, method: {}, query: {} }); try { handler.getClientCredentials(request); @@ -657,13 +657,13 @@ describe('TokenHandler integration', function() { describe('with `client_id` and grant type is `password` and `requireClientAuthentication` is false', function() { it('should return a client', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, requireClientAuthentication: { password: false} }); - var request = new Request({ body: { client_id: 'foo', grant_type: 'password' }, headers: {}, method: {}, query: {} }); - var credentials = handler.getClientCredentials(request); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, requireClientAuthentication: { password: false} }); + const request = new Request({ body: { client_id: 'foo', grant_type: 'password' }, headers: {}, method: {}, query: {} }); + const credentials = handler.getClientCredentials(request); credentials.should.eql({ clientId: 'foo' }); }); @@ -671,12 +671,12 @@ describe('TokenHandler integration', function() { describe('with `client_id` and `client_secret` in the request header as basic auth', function() { it('should return a client', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: { 'authorization': util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) @@ -684,7 +684,7 @@ describe('TokenHandler integration', function() { method: {}, query: {} }); - var credentials = handler.getClientCredentials(request); + const credentials = handler.getClientCredentials(request); credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); }); @@ -692,13 +692,13 @@ describe('TokenHandler integration', function() { describe('with `client_id` and `client_secret` in the request body', function() { it('should return a client', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, method: {}, query: {} }); - var credentials = handler.getClientCredentials(request); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, method: {}, query: {} }); + const credentials = handler.getClientCredentials(request); credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); }); @@ -707,12 +707,12 @@ describe('TokenHandler integration', function() { describe('handleGrantType()', function() { it('should throw an error if `grant_type` is missing', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { handler.handleGrantType(request); @@ -725,12 +725,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `grant_type` is invalid', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: '~foo~' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: '~foo~' }, headers: {}, method: {}, query: {} }); try { handler.handleGrantType(request); @@ -743,12 +743,12 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `grant_type` is unsupported', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'foobar' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: 'foobar' }, headers: {}, method: {}, query: {} }); try { handler.handleGrantType(request); @@ -761,13 +761,13 @@ describe('TokenHandler integration', function() { }); it('should throw an error if `grant_type` is unauthorized', function() { - var client = { grants: ['client_credentials'] }; - var model = { + const client = { grants: ['client_credentials'] }; + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'password' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: 'password' }, headers: {}, method: {}, query: {} }); try { handler.handleGrantType(request, client); @@ -780,14 +780,14 @@ describe('TokenHandler integration', function() { }); it('should throw an invalid grant error if a non-oauth error is thrown', function() { - var client = { grants: ['password'] }; - var model = { + const client = { grants: ['password'] }; + const model = { getClient: function(clientId, password, callback) { callback(null, client); }, getUser: function(uid, pwd, callback) { callback(); }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { grant_type: 'password', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: 'password', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); return handler.handleGrantType(request, client) .then(should.fail) @@ -799,17 +799,17 @@ describe('TokenHandler integration', function() { describe('with grant_type `authorization_code`', function() { it('should return a token', function() { - var client = { id: 'foobar', grants: ['authorization_code'] }; - var token = {}; - var model = { + const client = { id: 'foobar', grants: ['authorization_code'] }; + const token = {}; + const model = { getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, getClient: function() {}, saveToken: function() { return token; }, validateScope: function() { return 'foo'; }, revokeAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() / 2), user: {} }; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { code: 12345, grant_type: 'authorization_code' @@ -829,16 +829,16 @@ describe('TokenHandler integration', function() { describe('with grant_type `client_credentials`', function() { it('should return a token', function() { - var client = { grants: ['client_credentials'] }; - var token = {}; - var model = { + const client = { grants: ['client_credentials'] }; + const token = {}; + const model = { getClient: function() {}, getUserFromClient: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: 'client_credentials', scope: 'foo' @@ -858,16 +858,16 @@ describe('TokenHandler integration', function() { describe('with grant_type `password`', function() { it('should return a token', function() { - var client = { grants: ['password'] }; - var token = {}; - var model = { + const client = { grants: ['password'] }; + const token = {}; + const model = { getClient: function() {}, getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'baz'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', @@ -891,16 +891,16 @@ describe('TokenHandler integration', function() { describe('with grant_type `refresh_token`', function() { it('should return a token', function() { - var client = { grants: ['refresh_token'] }; - var token = { accessToken: 'foo', client: {}, user: {} }; - var model = { + const client = { grants: ['refresh_token'] }; + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { getClient: function() {}, getRefreshToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; }, saveToken: function() { return token; }, revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { grant_type: 'refresh_token', refresh_token: 12345 @@ -920,16 +920,16 @@ describe('TokenHandler integration', function() { describe('with custom grant_type', function() { it('should return a token', function() { - var client = { grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'] }; - var token = {}; - var model = { + const client = { grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'] }; + const token = {}; + const model = { getClient: function() {}, getUser: function() { return {}; }, saveToken: function() { return token; }, validateScope: function() { return 'foo'; } }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, extendedGrantTypes: { 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType } }); - var request = new Request({ body: { grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, extendedGrantTypes: { 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType } }); + const request = new Request({ body: { grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); return handler.handleGrantType(request, client) .then(function(data) { @@ -942,23 +942,23 @@ describe('TokenHandler integration', function() { describe('getAccessTokenLifetime()', function() { it('should return the client access token lifetime', function() { - var client = { accessTokenLifetime: 60 }; - var model = { + const client = { accessTokenLifetime: 60 }; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getAccessTokenLifetime(client).should.equal(60); }); it('should return the default access token lifetime', function() { - var client = {}; - var model = { + const client = {}; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getAccessTokenLifetime(client).should.equal(120); }); @@ -966,23 +966,23 @@ describe('TokenHandler integration', function() { describe('getRefreshTokenLifetime()', function() { it('should return the client access token lifetime', function() { - var client = { refreshTokenLifetime: 60 }; - var model = { + const client = { refreshTokenLifetime: 60 }; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getRefreshTokenLifetime(client).should.equal(60); }); it('should return the default access token lifetime', function() { - var client = {}; - var model = { + const client = {}; + const model = { getClient: function() { return client; }, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getRefreshTokenLifetime(client).should.equal(120); }); @@ -990,25 +990,25 @@ describe('TokenHandler integration', function() { describe('getTokenType()', function() { it('should return a token type', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = handler.getTokenType({ accessToken: 'foo', refreshToken: 'bar', scope: 'foobar' }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const tokenType = handler.getTokenType({ accessToken: 'foo', refreshToken: 'bar', scope: 'foobar' }); tokenType.should.deep.include({ accessToken: 'foo', accessTokenLifetime: undefined, refreshToken: 'bar', scope: 'foobar' }); }); }); describe('updateSuccessResponse()', function() { it('should set the `body`', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const tokenType = new BearerTokenType('foo', 'bar', 'biz'); + const response = new Response({ body: {}, headers: {} }); handler.updateSuccessResponse(response, tokenType); @@ -1016,13 +1016,13 @@ describe('TokenHandler integration', function() { }); it('should set the `Cache-Control` header', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const tokenType = new BearerTokenType('foo', 'bar', 'biz'); + const response = new Response({ body: {}, headers: {} }); handler.updateSuccessResponse(response, tokenType); @@ -1030,13 +1030,13 @@ describe('TokenHandler integration', function() { }); it('should set the `Pragma` header', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var tokenType = new BearerTokenType('foo', 'bar', 'biz'); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const tokenType = new BearerTokenType('foo', 'bar', 'biz'); + const response = new Response({ body: {}, headers: {} }); handler.updateSuccessResponse(response, tokenType); @@ -1046,13 +1046,13 @@ describe('TokenHandler integration', function() { describe('updateErrorResponse()', function() { it('should set the `body`', function() { - var error = new AccessDeniedError('Cannot request a token'); - var model = { + const error = new AccessDeniedError('Cannot request a token'); + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const response = new Response({ body: {}, headers: {} }); handler.updateErrorResponse(response, error); @@ -1061,13 +1061,13 @@ describe('TokenHandler integration', function() { }); it('should set the `status`', function() { - var error = new AccessDeniedError('Cannot request a token'); - var model = { + const error = new AccessDeniedError('Cannot request a token'); + const model = { getClient: function() {}, saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var response = new Response({ body: {}, headers: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const response = new Response({ body: {}, headers: {} }); handler.updateErrorResponse(response, error); diff --git a/test/integration/request_test.js b/test/integration/request_test.js index a62309d..e0c98f1 100644 --- a/test/integration/request_test.js +++ b/test/integration/request_test.js @@ -4,9 +4,9 @@ * Module dependencies. */ -var Request = require('../../lib/request'); -var InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); -var should = require('chai').should(); +const Request = require('../../lib/request'); +const InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); +const should = require('chai').should(); /** * Test `Request` integration. @@ -48,25 +48,25 @@ describe('Request integration', function() { }); it('should set the `body`', function() { - var request = new Request({ body: 'foo', headers: {}, method: {}, query: {} }); + const request = new Request({ body: 'foo', headers: {}, method: {}, query: {} }); request.body.should.equal('foo'); }); it('should set the `headers`', function() { - var request = new Request({ body: {}, headers: { foo: 'bar', QuX: 'biz' }, method: {}, query: {} }); + const request = new Request({ body: {}, headers: { foo: 'bar', QuX: 'biz' }, method: {}, query: {} }); request.headers.should.eql({ foo: 'bar', qux: 'biz' }); }); it('should set the `method`', function() { - var request = new Request({ body: {}, headers: {}, method: 'biz', query: {} }); + const request = new Request({ body: {}, headers: {}, method: 'biz', query: {} }); request.method.should.equal('biz'); }); it('should set the `query`', function() { - var request = new Request({ body: {}, headers: {}, method: {}, query: 'baz' }); + const request = new Request({ body: {}, headers: {}, method: {}, query: 'baz' }); request.query.should.equal('baz'); }); @@ -74,13 +74,13 @@ describe('Request integration', function() { describe('get()', function() { it('should return `undefined` if the field does not exist', function() { - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); (undefined === request.get('content-type')).should.be.true; }); it('should return the value if the field exists', function() { - var request = new Request({ + const request = new Request({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8' @@ -95,7 +95,7 @@ describe('Request integration', function() { describe('is()', function() { it('should accept an array of `types`', function() { - var request = new Request({ + const request = new Request({ body: {}, headers: { 'content-type': 'application/json', @@ -109,7 +109,7 @@ describe('Request integration', function() { }); it('should accept multiple `types` as arguments', function() { - var request = new Request({ + const request = new Request({ body: {}, headers: { 'content-type': 'application/json', @@ -123,7 +123,7 @@ describe('Request integration', function() { }); it('should return the first matching type', function() { - var request = new Request({ + const request = new Request({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8', @@ -137,7 +137,7 @@ describe('Request integration', function() { }); it('should return `false` if none of the `types` match', function() { - var request = new Request({ + const request = new Request({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8', @@ -151,7 +151,7 @@ describe('Request integration', function() { }); it('should return `false` if the request has no body', function() { - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); request.is('text/html').should.be.false; }); diff --git a/test/integration/response-types/code-response-type_test.js b/test/integration/response-types/code-response-type_test.js index e03b4a2..44bd53b 100644 --- a/test/integration/response-types/code-response-type_test.js +++ b/test/integration/response-types/code-response-type_test.js @@ -4,10 +4,10 @@ * Module dependencies. */ -var CodeResponseType = require('../../../lib/response-types/code-response-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var should = require('chai').should(); -var url = require('url'); +const CodeResponseType = require('../../../lib/response-types/code-response-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const should = require('chai').should(); +const url = require('url'); /** * Test `CodeResponseType` integration. @@ -27,7 +27,7 @@ describe('CodeResponseType integration', function() { }); it('should set the `code`', function() { - var responseType = new CodeResponseType('foo'); + const responseType = new CodeResponseType('foo'); responseType.code.should.equal('foo'); }); @@ -35,7 +35,7 @@ describe('CodeResponseType integration', function() { describe('buildRedirectUri()', function() { it('should throw an error if the `redirectUri` is missing', function() { - var responseType = new CodeResponseType('foo'); + const responseType = new CodeResponseType('foo'); try { responseType.buildRedirectUri(); @@ -48,15 +48,15 @@ describe('CodeResponseType integration', function() { }); it('should return the new redirect uri and set the `code` and `state` in the query', function() { - var responseType = new CodeResponseType('foo'); - var redirectUri = responseType.buildRedirectUri('http://example.com/cb'); + const responseType = new CodeResponseType('foo'); + const redirectUri = responseType.buildRedirectUri('http://example.com/cb'); url.format(redirectUri).should.equal('http://example.com/cb?code=foo'); }); it('should return the new redirect uri and append the `code` and `state` in the query', function() { - var responseType = new CodeResponseType('foo'); - var redirectUri = responseType.buildRedirectUri('http://example.com/cb?foo=bar'); + const responseType = new CodeResponseType('foo'); + const redirectUri = responseType.buildRedirectUri('http://example.com/cb?foo=bar'); url.format(redirectUri).should.equal('http://example.com/cb?foo=bar&code=foo'); }); diff --git a/test/integration/response_test.js b/test/integration/response_test.js index 1e1e020..d6c37e4 100644 --- a/test/integration/response_test.js +++ b/test/integration/response_test.js @@ -4,7 +4,7 @@ * Module dependencies. */ -var Response = require('../../lib/response'); +const Response = require('../../lib/response'); /** * Test `Response` integration. @@ -13,19 +13,19 @@ var Response = require('../../lib/response'); describe('Response integration', function() { describe('constructor()', function() { it('should set the `body`', function() { - var response = new Response({ body: 'foo', headers: {} }); + const response = new Response({ body: 'foo', headers: {} }); response.body.should.equal('foo'); }); it('should set the `headers`', function() { - var response = new Response({ body: {}, headers: { foo: 'bar', QuX: 'biz' } }); + const response = new Response({ body: {}, headers: { foo: 'bar', QuX: 'biz' } }); response.headers.should.eql({ foo: 'bar', qux: 'biz' }); }); it('should set the `status` to 200', function() { - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); response.status.should.equal(200); }); @@ -33,13 +33,13 @@ describe('Response integration', function() { describe('get()', function() { it('should return `undefined` if the field does not exist', function() { - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); (undefined === response.get('content-type')).should.be.true; }); it('should return the value if the field exists', function() { - var response = new Response({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8' } }); + const response = new Response({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8' } }); response.get('Content-Type').should.equal('text/html; charset=utf-8'); }); @@ -47,7 +47,7 @@ describe('Response integration', function() { describe('redirect()', function() { it('should set the location header to `url`', function() { - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); response.redirect('http://example.com'); @@ -55,7 +55,7 @@ describe('Response integration', function() { }); it('should set the `status` to 302', function() { - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); response.redirect('http://example.com'); @@ -65,7 +65,7 @@ describe('Response integration', function() { describe('set()', function() { it('should set the `field`', function() { - var response = new Response({ body: {}, headers: {} }); + const response = new Response({ body: {}, headers: {} }); response.set('foo', 'bar'); diff --git a/test/integration/server_test.js b/test/integration/server_test.js index 1851e21..db10544 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); -var Promise = require('bluebird'); -var Request = require('../../lib/request'); -var Response = require('../../lib/response'); -var Server = require('../../lib/server'); -var should = require('chai').should(); +const InvalidArgumentError = require('../../lib/errors/invalid-argument-error'); +const Promise = require('bluebird'); +const Request = require('../../lib/request'); +const Response = require('../../lib/response'); +const Server = require('../../lib/server'); +const should = require('chai').should(); /** * Test `Server` integration. @@ -29,8 +29,8 @@ describe('Server integration', function() { }); it('should set the `model`', function() { - var model = {}; - var server = new Server({ model: model }); + const model = {}; + const server = new Server({ model: model }); server.options.model.should.equal(model); }); @@ -38,7 +38,7 @@ describe('Server integration', function() { describe('authenticate()', function() { it('should set the default `options`', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -46,9 +46,9 @@ describe('Server integration', function() { }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); return server.authenticate(request, response) .then(function() { @@ -60,7 +60,7 @@ describe('Server integration', function() { }); it('should return a promise', function() { - var model = { + const model = { getAccessToken: function(token, callback) { callback(null, { user: {}, @@ -68,16 +68,16 @@ describe('Server integration', function() { }); } }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.authenticate(request, response); + const server = new Server({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); + const handler = server.authenticate(request, response); handler.should.be.an.instanceOf(Promise); }); it('should support callbacks', function(next) { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -85,9 +85,9 @@ describe('Server integration', function() { }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const response = new Response({ body: {}, headers: {} }); server.authenticate(request, response, null, next); }); @@ -95,7 +95,7 @@ describe('Server integration', function() { describe('authorize()', function() { it('should set the default `options`', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -109,9 +109,9 @@ describe('Server integration', function() { return { authorizationCode: 123 }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); + const response = new Response({ body: {}, headers: {} }); return server.authorize(request, response) .then(function() { @@ -122,7 +122,7 @@ describe('Server integration', function() { }); it('should return a promise', function() { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -136,16 +136,16 @@ describe('Server integration', function() { return { authorizationCode: 123 }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.authorize(request, response); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); + const response = new Response({ body: {}, headers: {} }); + const handler = server.authorize(request, response); handler.should.be.an.instanceOf(Promise); }); it('should support callbacks', function(next) { - var model = { + const model = { getAccessToken: function() { return { user: {}, @@ -159,9 +159,9 @@ describe('Server integration', function() { return { authorizationCode: 123 }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); + const response = new Response({ body: {}, headers: {} }); server.authorize(request, response, null, next); }); @@ -169,7 +169,7 @@ describe('Server integration', function() { describe('token()', function() { it('should set the default `options`', function() { - var model = { + const model = { getClient: function() { return { grants: ['password'] }; }, @@ -181,9 +181,9 @@ describe('Server integration', function() { }, validateScope: function() { return 'foo'; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const response = new Response({ body: {}, headers: {} }); return server.token(request, response) .then(function() { @@ -194,7 +194,7 @@ describe('Server integration', function() { }); it('should return a promise', function() { - var model = { + const model = { getClient: function() { return { grants: ['password'] }; }, @@ -205,16 +205,16 @@ describe('Server integration', function() { return { accessToken: 1234, client: {}, user: {} }; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); - var handler = server.token(request, response); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const response = new Response({ body: {}, headers: {} }); + const handler = server.token(request, response); handler.should.be.an.instanceOf(Promise); }); it('should support callbacks', function(next) { - var model = { + const model = { getClient: function() { return { grants: ['password'] }; }, @@ -228,9 +228,9 @@ describe('Server integration', function() { return 'foo'; } }; - var server = new Server({ model: model }); - var request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); - var response = new Response({ body: {}, headers: {} }); + const server = new Server({ model: model }); + const request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const response = new Response({ body: {}, headers: {} }); server.token(request, response, null, next); }); diff --git a/test/integration/token-types/bearer-token-type_test.js b/test/integration/token-types/bearer-token-type_test.js index c8ad306..47b1daa 100644 --- a/test/integration/token-types/bearer-token-type_test.js +++ b/test/integration/token-types/bearer-token-type_test.js @@ -4,9 +4,9 @@ * Module dependencies. */ -var BearerTokenType = require('../../../lib/token-types/bearer-token-type'); -var InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); -var should = require('chai').should(); +const BearerTokenType = require('../../../lib/token-types/bearer-token-type'); +const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error'); +const should = require('chai').should(); /** * Test `BearerTokenType` integration. @@ -26,19 +26,19 @@ describe('BearerTokenType integration', function() { }); it('should set the `accessToken`', function() { - var responseType = new BearerTokenType('foo', 'bar'); + const responseType = new BearerTokenType('foo', 'bar'); responseType.accessToken.should.equal('foo'); }); it('should set the `accessTokenLifetime`', function() { - var responseType = new BearerTokenType('foo', 'bar'); + const responseType = new BearerTokenType('foo', 'bar'); responseType.accessTokenLifetime.should.equal('bar'); }); it('should set the `refreshToken`', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); + const responseType = new BearerTokenType('foo', 'bar', 'biz'); responseType.refreshToken.should.equal('biz'); }); @@ -46,8 +46,8 @@ describe('BearerTokenType integration', function() { describe('valueOf()', function() { it('should return the value representation', function() { - var responseType = new BearerTokenType('foo', 'bar'); - var value = responseType.valueOf(); + const responseType = new BearerTokenType('foo', 'bar'); + const value = responseType.valueOf(); value.should.eql({ access_token: 'foo', @@ -57,8 +57,8 @@ describe('BearerTokenType integration', function() { }); it('should not include the `expires_in` if not given', function() { - var responseType = new BearerTokenType('foo'); - var value = responseType.valueOf(); + const responseType = new BearerTokenType('foo'); + const value = responseType.valueOf(); value.should.eql({ access_token: 'foo', @@ -67,8 +67,8 @@ describe('BearerTokenType integration', function() { }); it('should set `refresh_token` if `refreshToken` is defined', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); - var value = responseType.valueOf(); + const responseType = new BearerTokenType('foo', 'bar', 'biz'); + const value = responseType.valueOf(); value.should.eql({ access_token: 'foo', @@ -79,8 +79,8 @@ describe('BearerTokenType integration', function() { }); it('should set `expires_in` if `accessTokenLifetime` is defined', function() { - var responseType = new BearerTokenType('foo', 'bar', 'biz'); - var value = responseType.valueOf(); + const responseType = new BearerTokenType('foo', 'bar', 'biz'); + const value = responseType.valueOf(); value.should.eql({ access_token: 'foo', diff --git a/test/integration/utils/token-util_test.js b/test/integration/utils/token-util_test.js index b6aa650..d4f368e 100644 --- a/test/integration/utils/token-util_test.js +++ b/test/integration/utils/token-util_test.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var TokenUtil = require('../../../lib/utils/token-util'); -var should = require('chai').should(); +const TokenUtil = require('../../../lib/utils/token-util'); +const should = require('chai').should(); /** * Test `TokenUtil` integration. diff --git a/test/unit/grant-types/abstract-grant-type_test.js b/test/unit/grant-types/abstract-grant-type_test.js index d2ccf72..f6cb13a 100644 --- a/test/unit/grant-types/abstract-grant-type_test.js +++ b/test/unit/grant-types/abstract-grant-type_test.js @@ -4,9 +4,9 @@ * Module dependencies. */ -var AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); -var sinon = require('sinon'); -var should = require('chai').should(); +const AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `AbstractGrantType`. @@ -15,10 +15,10 @@ var should = require('chai').should(); describe('AbstractGrantType', function() { describe('generateAccessToken()', function() { it('should call `model.generateAccessToken()`', function() { - var model = { + const model = { generateAccessToken: sinon.stub().returns({ client: {}, expiresAt: new Date(), user: {} }) }; - var handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); return handler.generateAccessToken() .then(function() { @@ -31,10 +31,10 @@ describe('AbstractGrantType', function() { describe('generateRefreshToken()', function() { it('should call `model.generateRefreshToken()`', function() { - var model = { + const model = { generateRefreshToken: sinon.stub().returns({ client: {}, expiresAt: new Date(new Date() / 2), user: {} }) }; - var handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); return handler.generateRefreshToken() .then(function() { diff --git a/test/unit/grant-types/authorization-code-grant-type_test.js b/test/unit/grant-types/authorization-code-grant-type_test.js index a9220cb..83cc854 100644 --- a/test/unit/grant-types/authorization-code-grant-type_test.js +++ b/test/unit/grant-types/authorization-code-grant-type_test.js @@ -4,11 +4,11 @@ * Module dependencies. */ -var AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); -var Promise = require('bluebird'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('chai').should(); +const AuthorizationCodeGrantType = require('../../../lib/grant-types/authorization-code-grant-type'); +const Promise = require('bluebird'); +const Request = require('../../../lib/request'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `AuthorizationCodeGrantType`. @@ -17,14 +17,14 @@ var should = require('chai').should(); describe('AuthorizationCodeGrantType', function() { describe('getAuthorizationCode()', function() { it('should call `model.getAuthorizationCode()`', function() { - var model = { + const model = { getAuthorizationCode: sinon.stub().returns({ authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() * 2), user: {} }), revokeAuthorizationCode: function() {}, saveToken: function() {} }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); - var client = {}; + const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const client = {}; return handler.getAuthorizationCode(request, client) .then(function() { @@ -39,13 +39,13 @@ describe('AuthorizationCodeGrantType', function() { describe('revokeAuthorizationCode()', function() { it('should call `model.revokeAuthorizationCode()`', function() { - var model = { + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: sinon.stub().returns(true), saveToken: function() {} }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - var authorizationCode = {}; + const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); + const authorizationCode = {}; return handler.revokeAuthorizationCode(authorizationCode) .then(function() { @@ -60,14 +60,14 @@ describe('AuthorizationCodeGrantType', function() { describe('saveToken()', function() { it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getAuthorizationCode: function() {}, revokeAuthorizationCode: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); sinon.stub(handler, 'validateScope').returns('foobiz'); sinon.stub(handler, 'generateAccessToken').returns(Promise.resolve('foo')); diff --git a/test/unit/grant-types/client-credentials-grant-type_test.js b/test/unit/grant-types/client-credentials-grant-type_test.js index 4b1c8b6..3997823 100644 --- a/test/unit/grant-types/client-credentials-grant-type_test.js +++ b/test/unit/grant-types/client-credentials-grant-type_test.js @@ -4,9 +4,9 @@ * Module dependencies. */ -var ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); -var sinon = require('sinon'); -var should = require('chai').should(); +const ClientCredentialsGrantType = require('../../../lib/grant-types/client-credentials-grant-type'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `ClientCredentialsGrantType`. @@ -15,12 +15,12 @@ var should = require('chai').should(); describe('ClientCredentialsGrantType', function() { describe('getUserFromClient()', function() { it('should call `model.getUserFromClient()`', function() { - var model = { + const model = { getUserFromClient: sinon.stub().returns(true), saveToken: function() {} }; - var handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - var client = {}; + const handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const client = {}; return handler.getUserFromClient(client) .then(function() { @@ -35,13 +35,13 @@ describe('ClientCredentialsGrantType', function() { describe('saveToken()', function() { it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getUserFromClient: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); sinon.stub(handler, 'validateScope').returns('foobar'); sinon.stub(handler, 'generateAccessToken').returns('foo'); diff --git a/test/unit/grant-types/password-grant-type_test.js b/test/unit/grant-types/password-grant-type_test.js index c99c2ef..ceb2ad9 100644 --- a/test/unit/grant-types/password-grant-type_test.js +++ b/test/unit/grant-types/password-grant-type_test.js @@ -4,10 +4,10 @@ * Module dependencies. */ -var PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('chai').should(); +const PasswordGrantType = require('../../../lib/grant-types/password-grant-type'); +const Request = require('../../../lib/request'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `PasswordGrantType`. @@ -16,12 +16,12 @@ var should = require('chai').should(); describe('PasswordGrantType', function() { describe('getUser()', function() { it('should call `model.getUser()`', function() { - var model = { + const model = { getUser: sinon.stub().returns(true), saveToken: function() {} }; - var handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); return handler.getUser(request) .then(function() { @@ -37,13 +37,13 @@ describe('PasswordGrantType', function() { describe('saveToken()', function() { it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getUser: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); sinon.stub(handler, 'validateScope').returns('foobar'); sinon.stub(handler, 'generateAccessToken').returns('foo'); diff --git a/test/unit/grant-types/refresh-token-grant-type_test.js b/test/unit/grant-types/refresh-token-grant-type_test.js index 5775f43..c91a37e 100644 --- a/test/unit/grant-types/refresh-token-grant-type_test.js +++ b/test/unit/grant-types/refresh-token-grant-type_test.js @@ -4,10 +4,10 @@ * Module dependencies. */ -var RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('chai').should(); +const RefreshTokenGrantType = require('../../../lib/grant-types/refresh-token-grant-type'); +const Request = require('../../../lib/request'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `RefreshTokenGrantType`. @@ -16,15 +16,15 @@ var should = require('chai').should(); describe('RefreshTokenGrantType', function() { describe('handle()', function() { it('should revoke the previous token', function() { - var token = { accessToken: 'foo', client: {}, user: {} }; - var model = { + const token = { accessToken: 'foo', client: {}, user: {} }; + const model = { getRefreshToken: function() { return token; }, saveToken: function() { return { accessToken: 'bar', client: {}, user: {} }; }, revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }) }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); - var client = {}; + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); + const client = {}; return handler.handle(request, client) .then(function() { @@ -39,14 +39,14 @@ describe('RefreshTokenGrantType', function() { describe('getRefreshToken()', function() { it('should call `model.getRefreshToken()`', function() { - var model = { + const model = { getRefreshToken: sinon.stub().returns({ accessToken: 'foo', client: {}, user: {} }), saveToken: function() {}, revokeToken: function() {} }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); - var client = {}; + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); + const client = {}; return handler.getRefreshToken(request, client) .then(function() { @@ -61,13 +61,13 @@ describe('RefreshTokenGrantType', function() { describe('revokeToken()', function() { it('should call `model.revokeToken()`', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), saveToken: function() {} }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - var token = {}; + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const token = {}; return handler.revokeToken(token) .then(function() { @@ -80,13 +80,13 @@ describe('RefreshTokenGrantType', function() { }); it('should not call `model.revokeToken()`', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), saveToken: function() {} }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); - var token = {}; + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); + const token = {}; return handler.revokeToken(token) .then(function() { @@ -96,13 +96,13 @@ describe('RefreshTokenGrantType', function() { }); it('should not call `model.revokeToken()`', function() { - var model = { + const model = { getRefreshToken: function() {}, revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), saveToken: function() {} }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true }); - var token = {}; + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true }); + const token = {}; return handler.revokeToken(token) .then(function() { @@ -117,14 +117,14 @@ describe('RefreshTokenGrantType', function() { describe('saveToken()', function() { it('should call `model.saveToken()`', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); @@ -144,14 +144,14 @@ describe('RefreshTokenGrantType', function() { }); it('should call `model.saveToken()` without refresh token', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); @@ -171,14 +171,14 @@ describe('RefreshTokenGrantType', function() { }); it('should call `model.saveToken()` with refresh token', function() { - var client = {}; - var user = {}; - var model = { + const client = {}; + const user = {}; + const model = { getRefreshToken: function() {}, revokeToken: function() {}, saveToken: sinon.stub().returns(true) }; - var handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true}); + const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true}); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); diff --git a/test/unit/handlers/authenticate-handler_test.js b/test/unit/handlers/authenticate-handler_test.js index c280002..4d63428 100644 --- a/test/unit/handlers/authenticate-handler_test.js +++ b/test/unit/handlers/authenticate-handler_test.js @@ -4,11 +4,11 @@ * Module dependencies. */ -var AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); -var Request = require('../../../lib/request'); -var sinon = require('sinon'); -var should = require('chai').should(); -var ServerError = require('../../../lib/errors/server-error'); +const AuthenticateHandler = require('../../../lib/handlers/authenticate-handler'); +const Request = require('../../../lib/request'); +const sinon = require('sinon'); +const should = require('chai').should(); +const ServerError = require('../../../lib/errors/server-error'); /** * Test `AuthenticateHandler`. @@ -18,8 +18,8 @@ describe('AuthenticateHandler', function() { describe('getTokenFromRequest()', function() { describe('with bearer token in the request authorization header', function() { it('should call `getTokenFromRequestHeader()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, @@ -38,8 +38,8 @@ describe('AuthenticateHandler', function() { describe('with bearer token in the request query', function() { it('should call `getTokenFromRequestQuery()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: {}, headers: {}, method: {}, @@ -58,8 +58,8 @@ describe('AuthenticateHandler', function() { describe('with bearer token in the request body', function() { it('should call `getTokenFromRequestBody()`', function() { - var handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - var request = new Request({ + const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const request = new Request({ body: { access_token: 'foo' }, headers: {}, method: {}, @@ -79,10 +79,10 @@ describe('AuthenticateHandler', function() { describe('getAccessToken()', function() { it('should call `model.getAccessToken()`', function() { - var model = { + const model = { getAccessToken: sinon.stub().returns({ user: {} }) }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); return handler.getAccessToken('foo') .then(function() { @@ -97,12 +97,12 @@ describe('AuthenticateHandler', function() { describe('validateAccessToken()', function() { it('should fail if token has no valid `accessTokenExpiresAt` date', function() { - var model = { + const model = { getAccessToken: function() {} }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); - var failed = false; + let failed = false; try { handler.validateAccessToken({ user: {} @@ -116,10 +116,10 @@ describe('AuthenticateHandler', function() { }); it('should succeed if token has valid `accessTokenExpiresAt` date', function() { - var model = { + const model = { getAccessToken: function() {} }; - var handler = new AuthenticateHandler({ model: model }); + const handler = new AuthenticateHandler({ model: model }); try { handler.validateAccessToken({ user: {}, @@ -134,11 +134,11 @@ describe('AuthenticateHandler', function() { describe('verifyScope()', function() { it('should call `model.getAccessToken()` if scope is defined', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: sinon.stub().returns(true) }; - var handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'bar' }); + const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'bar' }); return handler.verifyScope('foo') .then(function() { diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js index 35ece25..376bc1e 100644 --- a/test/unit/handlers/authorize-handler_test.js +++ b/test/unit/handlers/authorize-handler_test.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); -var Request = require('../../../lib/request'); -var Response = require('../../../lib/response'); -var Promise = require('bluebird'); -var sinon = require('sinon'); -var should = require('chai').should(); +const AuthorizeHandler = require('../../../lib/handlers/authorize-handler'); +const Request = require('../../../lib/request'); +const Response = require('../../../lib/response'); +const Promise = require('bluebird'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `AuthorizeHandler`. @@ -18,13 +18,13 @@ var should = require('chai').should(); describe('AuthorizeHandler', function() { describe('generateAuthorizationCode()', function() { it('should call `model.generateAuthorizationCode()`', function() { - var model = { + const model = { generateAuthorizationCode: sinon.stub().returns({}), getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); return handler.generateAuthorizationCode() .then(function() { @@ -37,13 +37,13 @@ describe('AuthorizeHandler', function() { describe('getClient()', function() { it('should call `model.getClient()`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: sinon.stub().returns({ grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }), saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(function() { @@ -58,14 +58,14 @@ describe('AuthorizeHandler', function() { describe('getUser()', function() { it('should call `authenticateHandler.getUser()`', function() { - var authenticateHandler = { handle: sinon.stub().returns(Promise.resolve({})) }; - var model = { + const authenticateHandler = { handle: sinon.stub().returns(Promise.resolve({})) }; + const model = { getClient: function() {}, saveAuthorizationCode: function() {} }; - var handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); - var request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - var response = new Response(); + const handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const response = new Response(); return handler.getUser(request, response) .then(function() { @@ -80,12 +80,12 @@ describe('AuthorizeHandler', function() { describe('saveAuthorizationCode()', function() { it('should call `model.saveAuthorizationCode()`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: sinon.stub().returns({}) }; - var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); return handler.saveAuthorizationCode('foo', 'bar', 'qux', 'biz', 'baz', 'boz') .then(function() { @@ -99,4 +99,80 @@ describe('AuthorizeHandler', function() { .catch(should.fail); }); }); + + describe('validateRedirectUri()', function() { + it('should call `model.validateRedirectUri()`', function() { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const redirect_uri = 'http://example.com/cb/2'; + const model = { + getAccessToken: function() {}, + getClient: sinon.stub().returns(client), + saveAuthorizationCode: function() {}, + validateRedirectUri: sinon.stub().returns(true) + }; + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(function() { + model.getClient.callCount.should.equal(1); + model.getClient.firstCall.args.should.have.length(2); + model.getClient.firstCall.args[0].should.equal(12345); + model.getClient.firstCall.thisValue.should.equal(model); + + model.validateRedirectUri.callCount.should.equal(1); + model.validateRedirectUri.firstCall.args.should.have.length(2); + model.validateRedirectUri.firstCall.args[0].should.equal(redirect_uri); + model.validateRedirectUri.firstCall.args[1].should.equal(client); + model.validateRedirectUri.firstCall.thisValue.should.equal(model); + }) + .catch(should.fail); + }); + + it('should be successful validation', function () { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const redirect_uri = 'http://example.com/cb'; + const model = { + getAccessToken: function() {}, + getClient: sinon.stub().returns(client), + saveAuthorizationCode: function() {}, + validateRedirectUri: function (redirectUri, client) { + return client.redirectUris.includes(redirectUri); + } + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then((client) => { + client.should.equal(client); + }); + }); + + it('should be unsuccessful validation', function () { + const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const redirect_uri = 'http://example.com/callback'; + const model = { + getAccessToken: function() {}, + getClient: sinon.stub().returns(client), + saveAuthorizationCode: function() {}, + validateRedirectUri: function (redirectUri, client) { + return client.redirectUris.includes(redirectUri); + } + }; + + const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + + return handler.getClient(request) + .then(() => { + throw Error('should not resolve'); + }) + .catch((err) => { + err.name.should.equal('invalid_client'); + err.message.should.equal('Invalid client: `redirect_uri` does not match client value'); + }); + }); + }); }); diff --git a/test/unit/handlers/token-handler_test.js b/test/unit/handlers/token-handler_test.js index 4dd2199..8fe258b 100644 --- a/test/unit/handlers/token-handler_test.js +++ b/test/unit/handlers/token-handler_test.js @@ -4,10 +4,10 @@ * Module dependencies. */ -var Request = require('../../../lib/request'); -var TokenHandler = require('../../../lib/handlers/token-handler'); -var sinon = require('sinon'); -var should = require('chai').should(); +const Request = require('../../../lib/request'); +const TokenHandler = require('../../../lib/handlers/token-handler'); +const sinon = require('sinon'); +const should = require('chai').should(); /** * Test `TokenHandler`. @@ -16,12 +16,12 @@ var should = require('chai').should(); describe('TokenHandler', function() { describe('getClient()', function() { it('should call `model.getClient()`', function() { - var model = { + const model = { getClient: sinon.stub().returns({ grants: ['password'] }), saveToken: function() {} }; - var handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - var request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); + const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); return handler.getClient(request) .then(function() { diff --git a/test/unit/models/token-model_test.js b/test/unit/models/token-model_test.js index 6fa0110..7dcac61 100644 --- a/test/unit/models/token-model_test.js +++ b/test/unit/models/token-model_test.js @@ -1,5 +1,5 @@ -var TokenModel = require('../../../lib/models/token-model'); -var should = require('chai').should(); +const TokenModel = require('../../../lib/models/token-model'); +const should = require('chai').should(); /** * Test `Server`. */ @@ -7,17 +7,17 @@ var should = require('chai').should(); describe('Model', function() { describe('constructor()', function() { it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', function() { - var atExpiresAt = new Date(); + const atExpiresAt = new Date(); atExpiresAt.setHours(new Date().getHours() + 1); - var data = { + const data = { accessToken: 'foo', client: 'bar', user: 'tar', accessTokenExpiresAt: atExpiresAt }; - var model = new TokenModel(data); + const model = new TokenModel(data); should.exist(model.accessTokenLifetime); model.accessTokenLifetime.should.a('number'); model.accessTokenLifetime.should.be.approximately(3600, 2); diff --git a/test/unit/request_test.js b/test/unit/request_test.js index a86005a..f292e2b 100644 --- a/test/unit/request_test.js +++ b/test/unit/request_test.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var Request = require('../../lib/request'); -var should = require('chai').should(); +const Request = require('../../lib/request'); +const should = require('chai').should(); /** * Test `Request`. @@ -28,9 +28,9 @@ function generateBaseRequest() { describe('Request', function() { it('should instantiate with a basic request', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.headers.should.eql(originalRequest.headers); request.method.should.eql(originalRequest.method); request.query.should.eql(originalRequest.query); @@ -38,10 +38,10 @@ describe('Request', function() { }); it('should allow a request to be passed without a body', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); delete originalRequest.body; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.headers.should.eql(originalRequest.headers); request.method.should.eql(originalRequest.method); request.query.should.eql(originalRequest.query); @@ -49,7 +49,7 @@ describe('Request', function() { }); it('should throw if headers are not passed to the constructor', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); delete originalRequest.headers; (function() { @@ -58,7 +58,7 @@ describe('Request', function() { }); it('should throw if query string isn\'t passed to the constructor', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); delete originalRequest.query; (function() { @@ -67,7 +67,7 @@ describe('Request', function() { }); it('should throw if method isn\'t passed to the constructor', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); delete originalRequest.method; (function() { @@ -76,13 +76,13 @@ describe('Request', function() { }); it('should convert all header keys to lowercase', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); originalRequest.headers = { Foo: 'bar', BAR: 'foo' }; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.headers.foo.should.eql('bar'); request.headers.bar.should.eql('foo'); should.not.exist(request.headers.Foo); @@ -90,7 +90,7 @@ describe('Request', function() { }); it('should include additional properties passed in the request', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); originalRequest.custom = { newFoo: 'newBar' }; @@ -99,7 +99,7 @@ describe('Request', function() { newBar: 'newFoo' }; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.headers.should.eql(originalRequest.headers); request.method.should.eql(originalRequest.method); request.query.should.eql(originalRequest.query); @@ -109,7 +109,7 @@ describe('Request', function() { }); it('should include additional properties passed in the request', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); originalRequest.custom = { newFoo: 'newBar' }; @@ -118,7 +118,7 @@ describe('Request', function() { newBar: 'newFoo' }; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.headers.should.eql(originalRequest.headers); request.method.should.eql(originalRequest.method); request.query.should.eql(originalRequest.query); @@ -128,41 +128,41 @@ describe('Request', function() { }); it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); it('should allow getting of headers using `request.get`', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); it('should validate the content-type', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.is('application/x-www-form-urlencoded').should.eql('application/x-www-form-urlencoded'); }); it('should return false if the content-type is invalid', function() { - var originalRequest = generateBaseRequest(); + const originalRequest = generateBaseRequest(); originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; - var request = new Request(originalRequest); + const request = new Request(originalRequest); request.is('application/json').should.eql(false); }); }); diff --git a/test/unit/response_test.js b/test/unit/response_test.js index 0ef54a8..8d4897c 100644 --- a/test/unit/response_test.js +++ b/test/unit/response_test.js @@ -4,8 +4,8 @@ * Module dependencies. */ -var Response = require('../../lib/response'); -var should = require('chai').should(); +const Response = require('../../lib/response'); +const should = require('chai').should(); /** * Test `Request`. @@ -24,42 +24,42 @@ function generateBaseResponse() { describe('Request', function() { it('should instantiate with a basic request', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql(originalResponse.headers); response.body.should.eql(originalResponse.body); response.status.should.eql(200); }); it('should allow a response to be passed without a body', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); delete originalResponse.body; - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql(originalResponse.headers); response.body.should.eql({}); response.status.should.eql(200); }); it('should allow a response to be passed without headers', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); delete originalResponse.headers; - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql({}); response.body.should.eql(originalResponse.body); response.status.should.eql(200); }); it('should convert all header keys to lowercase', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); originalResponse.headers = { Foo: 'bar', BAR: 'foo' }; - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.foo.should.eql('bar'); response.headers.bar.should.eql('foo'); should.not.exist(response.headers.Foo); @@ -67,7 +67,7 @@ describe('Request', function() { }); it('should include additional properties passed in the response', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); originalResponse.custom = { newFoo: 'newBar' }; @@ -76,7 +76,7 @@ describe('Request', function() { newBar: 'newFoo' }; - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql(originalResponse.headers); response.body.should.eql(originalResponse.body); response.custom.should.eql(originalResponse.custom); @@ -84,23 +84,23 @@ describe('Request', function() { }); it('should allow getting of headers using `response.get`', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.get('bar').should.eql(originalResponse.headers.bar); }); it('should allow getting of headers using `response.get`', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.get('bar').should.eql(originalResponse.headers.bar); }); it('should allow setting of headers using `response.set`', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql(originalResponse.headers); response.set('newheader', 'newvalue'); response.headers.bar.should.eql('foo'); @@ -108,9 +108,9 @@ describe('Request', function() { }); it('should process redirect', function() { - var originalResponse = generateBaseResponse(); + const originalResponse = generateBaseResponse(); - var response = new Response(originalResponse); + const response = new Response(originalResponse); response.headers.should.eql(originalResponse.headers); response.status.should.eql(200); response.redirect('http://foo.bar'); diff --git a/test/unit/server_test.js b/test/unit/server_test.js index e7c343f..3987df7 100644 --- a/test/unit/server_test.js +++ b/test/unit/server_test.js @@ -4,12 +4,12 @@ * Module dependencies. */ -var AuthenticateHandler = require('../../lib/handlers/authenticate-handler'); -var AuthorizeHandler = require('../../lib/handlers/authorize-handler'); -var Promise = require('bluebird'); -var Server = require('../../lib/server'); -var TokenHandler = require('../../lib/handlers/token-handler'); -var sinon = require('sinon'); +const AuthenticateHandler = require('../../lib/handlers/authenticate-handler'); +const AuthorizeHandler = require('../../lib/handlers/authorize-handler'); +const Promise = require('bluebird'); +const Server = require('../../lib/server'); +const TokenHandler = require('../../lib/handlers/token-handler'); +const sinon = require('sinon'); /** * Test `Server`. @@ -18,10 +18,10 @@ var sinon = require('sinon'); describe('Server', function() { describe('authenticate()', function() { it('should call `handle`', function() { - var model = { + const model = { getAccessToken: function() {} }; - var server = new Server({ model: model }); + const server = new Server({ model: model }); sinon.stub(AuthenticateHandler.prototype, 'handle').returns(Promise.resolve()); @@ -33,11 +33,11 @@ describe('Server', function() { }); it('should map string passed as `options` to `options.scope`', function() { - var model = { + const model = { getAccessToken: function() {}, verifyScope: function() {} }; - var server = new Server({ model: model }); + const server = new Server({ model: model }); sinon.stub(AuthenticateHandler.prototype, 'handle').returns(Promise.resolve()); @@ -53,12 +53,12 @@ describe('Server', function() { describe('authorize()', function() { it('should call `handle`', function() { - var model = { + const model = { getAccessToken: function() {}, getClient: function() {}, saveAuthorizationCode: function() {} }; - var server = new Server({ model: model }); + const server = new Server({ model: model }); sinon.stub(AuthorizeHandler.prototype, 'handle').returns(Promise.resolve()); @@ -72,11 +72,11 @@ describe('Server', function() { describe('token()', function() { it('should call `handle`', function() { - var model = { + const model = { getClient: function() {}, saveToken: function() {} }; - var server = new Server({ model: model }); + const server = new Server({ model: model }); sinon.stub(TokenHandler.prototype, 'handle').returns(Promise.resolve()); diff --git a/test/unit/validator/is_test.js b/test/unit/validator/is_test.js deleted file mode 100644 index c6827d8..0000000 --- a/test/unit/validator/is_test.js +++ /dev/null @@ -1,127 +0,0 @@ -var is = require('../../../lib/validator/is'); -require('chai').should(); - -function runRanges (ranges, fn, expected) { - ranges.forEach(function (range) { - var lower = range[0]; - var upper = range[1]; - - for (var i = lower; i <= upper; i++) { - var unicodeChar = String.fromCodePoint(i); - // single char - fn(unicodeChar).should.eql(expected, i + ' ' + unicodeChar); - // multiple chars - fn(unicodeChar+unicodeChar).should.eql(expected, i + ' ' + unicodeChar); - } - }); -} - -describe('Validator', function () { - describe('is', function () { - it('validates if a value matches a unicode character (nchar)', function () { - var validRanges = [ - [45, 46], // \u002D \u002E - [48, 57], // 0-9 - [65, 90], // A-Z - [95, 95], // \u005F - [97, 122] // a-z - ]; - - runRanges(validRanges, is.nchar, true); - - var invalidRanges = [ - [0, 44], - [47, 47], - [58, 64], - [91, 94], - [96, 96], - [123, 1023] - ]; - - runRanges(invalidRanges, is.nchar, false); - }); - it('validates if a value matches a unicode character, including exclamation marks (nqchar)', function () { - var validRanges = [ - [33, 33], // \u0021 - [35, 91], // \u0023-\u005B - [93, 126] // \u005D-\u007E - ]; - - runRanges(validRanges, is.nqchar, true); - - var invalidRanges = [ - [0, 32], - [34, 34], - [92, 92], - [127, 1023] - ]; - - runRanges(invalidRanges, is.nqchar, false); - }); - it('validates if a value matches a unicode character, including exclamation marks and spaces (nqschar)', function () { - var validRanges = [ - [32, 33], // \u0020-\u0021 - [35, 91], // \u0023-\u005B - [93, 126] // \u005D-\u007E - ]; - - runRanges(validRanges, is.nqschar, true); - - var invalidRanges = [ - [0, 31], - [34, 34], - [92, 92], - [127, 1023] - ]; - - runRanges(invalidRanges, is.nqschar, false); - }); - it('validates if a value matches a unicode character excluding the carriage return and linefeed characters (uchar)', function () { - this.timeout(60000); - var validRanges = [ - [9, 9], // \u0009 - [32, 126], // \u0020-\u007E, - [128, 55295], // \u0080-\uD7FF - [57344, 65533], // \uE000-\uFFFD - [65536, 1114111] // \u10000-\u10FFFF - ]; - - runRanges(validRanges, is.uchar, true); - - var invalidRanges = [ - [0, 8], - [10, 31], - [127, 127], - [55296, 57343], - [65534, 65535] - ]; - - runRanges(invalidRanges, is.uchar, false); - }); - it('validates if a value matches generic URIs (uri)', function () { - ['aa:', 'http:', 'https:'].forEach(function (uri) { - is.uri(uri).should.equal(true); - is.uri(uri.toUpperCase()).should.equal(true); - }); - - ['a', 'a:', 'http'].forEach(function (uri) { - is.uri(uri).should.equal(false); - is.uri(uri.toUpperCase()).should.equal(false); - }); - }); - it('validates if a value matches against the printable set of unicode characters (vschar)', function () { - var validRanges = [ - [32, 126] // \u0020-\u007E - ]; - - runRanges(validRanges, is.vschar, true); - - var invalidRanges = [ - [0, 31], - [127, 1023] - ]; - - runRanges(invalidRanges, is.vschar, false); - }); - }); -});