Skip to content

Commit

Permalink
Merge branch 'release/1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasrafael committed Aug 7, 2019
2 parents 90b321e + 3c40a1f commit e444418
Show file tree
Hide file tree
Showing 14 changed files with 1,096 additions and 27 deletions.
23 changes: 20 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# webstorm settings
.idea

# Logs
logs
*.log
Expand Down Expand Up @@ -62,3 +59,23 @@ typings/

# next.js build output
.next

# IDE
.idea
.vscode

# Directory files dist
dist

# Docs
docs

# certificates and keys directories and files
*.pem
*.crt
*.key
*.csr
*.cert

# package-lock.json
package-lock.json
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
"name": "express-apigw-base-plugin",
"version": "1.0.0",
"version": "1.1.0",
"description": "Express Gateway Base Plugin",
"main": "manifest.js",
"author": "NUTES/UEPB",
"license": "Apache-2.0",
"scripts": {
"test:unit": "mocha --opts test/unit/mocha.opts test/unit/**/**-spec.js"
},
"dependencies": {
"axios": "^0.19.0",
"cors": "^2.8.5",
Expand All @@ -17,6 +20,7 @@
"chai": "^4.2.0",
"mocha": "^6.2.0",
"sinon": "^7.3.2",
"supertest": "^4.0.2"
"supertest": "^4.0.2",
"express-gateway": "^1.16.7"
}
}
13 changes: 5 additions & 8 deletions policies/auth/auth.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
/**
* Login Policy
*/
const jwt = require('jsonwebtoken')
let jwt = require('jsonwebtoken')
const fs = require('fs')
let userService = require('../../services/user-service')
let userService = require('../../services/http-client')
let gatewayService = require('express-gateway/lib/services')

module.exports = function (actionParams, authServiceTest, localServicesTest) {
return async (req, res, next) => {
// Test context, Mocks authService and services.
if (authServiceTest && localServicesTest) {
userService = authServiceTest
gatewayService = localServicesTest
gatewayService = localServicesTest.fakeGatewayUser
jwt = localServicesTest.fakeJwt
}

try {
// 1. Run authentication on the account-service
const authResponse = await userService.auth(actionParams.urlAuthService, req.body)
const authResponse = await userService.post(actionParams.urlAuthService, req.body)
const accessToken = authResponse.data.access_token

// 2. Read JWT public key
Expand All @@ -41,10 +42,6 @@ module.exports = function (actionParams, authServiceTest, localServicesTest) {

return res.status(200).send(authResponse.data)
} catch (err) {
/* Report in logs that JWT has an invalid signature */
if (err.name === 'JsonWebTokenError' && err.message === 'invalid signature') {
console.error(`[auth-policy] error: Invalid JWT Signature!`)
}
if (err.response && err.response.data) {
return res.status(err.response.status).send(err.response.data)
}
Expand Down
3 changes: 1 addition & 2 deletions policies/authentication/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ module.exports = function (actionParams, testContext) {
}, (jwtPayload, done) => {
// At this point both the jwt signature, issuer and experation were validated
// In addition, we have the jwt payload decoded and we can access its attributes
// console.log(`JWT payload: ${JSON.stringify(jwtPayload)}`);

// User validation. We expect to receive the username in the jwt 'sub' field
if (!jwtPayload.sub) return done(null, false)
Expand Down Expand Up @@ -77,7 +76,7 @@ module.exports = function (actionParams, testContext) {
'redirect_link': '/auth'
})

if (info && info.message === 'jwt issuer invalid. expected: ocariot') return res.status(401).send({
if (info && info.message === 'jwt issuer invalid.') return res.status(401).send({
'code': 401,
'message': 'UNAUTHORIZED',
'description': 'Authentication failed because the access token contains invalid parameters.',
Expand Down
4 changes: 2 additions & 2 deletions policies/authorization/jwt-scopes.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ module.exports = function (actionParams) {

return function (req, res, next) {
if (expectedScopes.length === 0) return next()
if (!req.user || typeof req.user.scopes !== 'string') return error(res)
if (!req.user || typeof req.user.scope !== 'string') return error(res)

const scopes = req.user.scopes.split(' ')
const scopes = req.user.scope.split(' ')
const allowed = expectedScopes.some(scope => scopes.indexOf(scope) !== -1)

return allowed ? next() : error(res)
Expand Down
38 changes: 29 additions & 9 deletions policies/delete-user/delete-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

let gatewayService = require('express-gateway/lib/services').user
let userService = require('../../services/user-service')
let userService = require('../../services/http-client')

module.exports = function (actionParams, userServiceGwTest, axiosTest) {
// Test context. Mocks serServiceGwTest and axiosTest
Expand All @@ -20,19 +20,39 @@ module.exports = function (actionParams, userServiceGwTest, axiosTest) {

try {
// 1. Delete user in account service.
await userService.delete(`${actionParams.urlDeleteService}/${userId}`)
const responseAccount = await userService.delete(`${actionParams.urlDeleteService}/${userId}`)

// 2. Find user at gateway and delete or skip if there is not.
// When the deleted user was not found in the gateway,
// it occurs when the user has not yet logged in to the platform.
const userGateway = await gatewayService.findByUsernameOrId(userId)
if (userGateway) await gatewayService.remove(userGateway.id)
await deleteUserGateway(userId)

return res.status(204).send()
return res.status(responseAccount.status).send(responseAccount.data)
} catch (err) {
console.error(new Date().toUTCString(), '| Error removing API Gateway user:', error.message)
return res.status(204).send()

if (err.response && err.response.status && err.response.data) {
return res.status(err.response.status).send(err.response.data)
}
return res.status(500).send({
'code': 500,
'message': 'INTERNAL SERVER ERROR',
'description': 'An internal server error has occurred.'
})
}
}
}


/**
* Function used to recover user and remove them from Gateway
* @param userId
* @returns {Promise<void>}
*/
async function deleteUserGateway(userId) {
try {
// When the deleted user was not found in the gateway,
// it occurs when the user has not yet logged in to the platform.
const userGateway = await gatewayService.findByUsernameOrId(userId)
if (userGateway) await gatewayService.remove(userGateway.id)
} catch (err) {
console.error(new Date().toISOString(), '| Error Removing User on Gateway:\n', err)
}
}
2 changes: 1 addition & 1 deletion services/user-service.js → services/http-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const instance = axios.create({
})

module.exports = {
auth: function (url, credentials) {
post: function (url, credentials) {
return instance.post(url, credentials)
},

Expand Down
13 changes: 13 additions & 0 deletions test/unit/certs/fake-certs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = '-----BEGIN RSA PUBLIC KEY-----\n' +
'MIICCgKCAgEA0YjRFQg5J3qNOM/OuxZYcJq4vmGO6hZpgrHBHDSs0TCwLIuDylI6\n' +
'nrBFWaflSCgoIRzNVHvV6NxO+Ucu4ORoEbCjea47bW6UTItyAt82s1aLNWQ0sSkI\n' +
'29N7qynPCT8+9flfgnh959G6Rh20P6pfM98rg/0kTEfI31dTo5pdd8coDoX98V1+\n' +
'pHUpdMBICr37p6HjX8SyXRNyfLUg6tRE/58pIMyCZTEYwarwIZCOUDm0QEZbCFpF\n' +
'D5d7EJTAKD3Al9Q97B5XZbYrTyR6RrnvK9/HeyUuj0RmXiaEt6cbcjzBTrcmoqju\n' +
'uVnrqxpejEXxVK1+xwBsRxBZqhvBiaPZj+R+TCQVeUVq9Uw0BxkGPaq70Dl2uOVO\n' +
'fsrMdVzDYNA5UOE2i6Kf5nKlAxhZh9ZubBoYCeZquw7vghbB3q/hbq+xQtedqUbL\n' +
'yYFhFzpAl+5BtI/g1zr6Ew5tQJx6OPSXZEJmDE/h9jmPc122iQJZbjaRJLM44sa6\n' +
'+fJIoWms+hZjqkeCd2yaBg7FE0nOj4ZJb8i5Xz+QKOd3pr2xPr7q+tMuhaf/9dLf\n' +
'gTwZmZHp6Iu8LfzllIl+4MGXgnH76eyoOESvhha0aD4GbEW7a6AiRBlZWmuQQJF3\n' +
'yTfnHPDetKI87hmzVbLTmZ6hjKOfsfUqOvqC1UQdH8HNfT4TM2+vQYkCAwEAAQ==\n' +
'-----END RSA PUBLIC KEY-----\n'
78 changes: 78 additions & 0 deletions test/unit/conditions/regex-path-method-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const condition = require('../../../conditions/regex-path-method')
const assert = require('chai').assert

describe('Condition: regex-path-method', () => {
describe('Integrity', () => {
it('Field "name" is type valid', () => {
assert.typeOf(condition.name, 'string', '"name" is not string type')
assert.equal(condition.name, 'regex-path-method', 'Condition name other than expected')
})
it('Field "handler" is type valid', () => {
assert.typeOf(condition.handler, 'function', '"handler" is not function type')
})
it('Field "schema" is type valid', () => {
assert.typeOf(condition.schema, 'object', '"schema" is not object type')
})
it('Field "schema.$id" is type valid', () => {
assert.typeOf(condition.schema.$id, 'string', '"schema.$id" is not string type')
assert.equal(condition.schema.$id, 'http://express-gateway.io/schemas/conditions/regex-path-method.json', '"schema.$id" different than expected')
})
it('Field "schema.type" is type valid', () => {
assert.typeOf(condition.schema.type, 'string', '"schema.type" is not object type')
assert.equal(condition.schema.type, 'object', '"schema.type" different than expected')
})
it('Field "schema.properties" is type valid', () => {
assert.typeOf(condition.schema.properties, 'object', '"schema.properties" is not object type')
})
it('Field "schema.properties.regexpath" is type valid', () => {
assert.typeOf(condition.schema.properties.regexPath, 'object', '"schema.properties.regexpath" is not object type')
assert.typeOf(condition.schema.properties.regexPath.type, 'string', '"schema.properties.regexpath" is not object string type')
})
it('Field "schema.properties.method" is type valid', () => {
assert.typeOf(condition.schema.properties.method, 'object', '"schema.properties.method" is not object type')
assert.typeOf(condition.schema.properties.method.type, 'string', '"schema.properties.method" is not object string type')
})
it('Field "schema.required" is type valid', () => {
assert.typeOf(condition.schema.required, 'array', '"schema.required" is not array type')
assert.equal(condition.schema.required[0], 'regexPath', '"schema.required" different than expected')
})

})

describe('Functionality', () => {
it('When the request matches the all settings', () => {
const req = {
url: '/v1/auth',
method: 'POST'
}
const conditionConfig = {
regexPath: '^(/v1/auth)$',
method: 'POST'
}
assert.equal(true, condition.handler(req, conditionConfig), 'Handler should return "true"')
})
it('When the request matches the regexPath but not the method', () => {
const req = {
url: '/v1/auth',
method: 'GET'
}
const conditionConfig = {
regexPath: '^(/v1/auth)$',
method: 'POST'
}
assert.equal(false, condition.handler(req, conditionConfig), 'Handler should return "false"')
})
it('When the request not matches the any settings', () => {
const req = {
url: '/users/fakeid',
method: 'GET'
}
const conditionConfig = {
regexPath: '^(/v1/auth)$',
method: 'POST'
}
assert.equal(false, condition.handler(req, conditionConfig), 'Handler should return "false"')
})

})
})
4 changes: 4 additions & 0 deletions test/unit/mocha.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--reporter spec
--slow 5000
--timeout 5000
--exit
Loading

0 comments on commit e444418

Please sign in to comment.