Browse Source

Phase III Task 6

master
Yutsuo 7 years ago
parent
commit
a1b9f48278
  1. 4
      README.md
  2. 355
      node/app.js
  3. 0
      node/html/nay.html
  4. 3
      node/html/yay.html

4
README.md

@ -21,3 +21,7 @@ Crie um endpoint REST '/restricted' que receba o token JWT e retorne o JSON "{me
Quinta tarefa: Quinta tarefa:
Altere o serviço '/restricted' e adicione ao cabeçalho HTTP de retorno 'HOSTNAME=[container-hostname]' para identificarmos a instância do container que atendeu à requisição. Mande o print da chamada cURL mostrando esse cabeçalho HTTP na resposta. Altere o serviço '/restricted' e adicione ao cabeçalho HTTP de retorno 'HOSTNAME=[container-hostname]' para identificarmos a instância do container que atendeu à requisição. Mande o print da chamada cURL mostrando esse cabeçalho HTTP na resposta.
Sexta tarefa:
Levante a página e o serviço REST em Swarm Mode. Escale o container do NodeJS para 6 instâncias e do NGINX para 3 instâncias. Altere a página HTML para mostrar o nome do hostname retornado no cabeçalho de /restricted pra vc saber qual instância te respondeu. Mande o print da página HTML funcionando, demonstrando que a cada requisição uma instância diferente de NodeJS responde à requisição.

355
node/app.js

@ -1,45 +1,48 @@
'use strict' 'use strict'
const express = require('express'); const express = require('express')
const app = express(); const app = express()
const mongoose = require('mongoose'); const mongoose = require('mongoose')
const Schema = mongoose.Schema; const Schema = mongoose.Schema
const database = 'mongodb://' + process.env.mongousr + ':' + process.env.mongopwd + '@mongo:27017/test'; const database = 'mongodb://' + process.env.mongousr + ':' + process.env.mongopwd + '@mongo:27017/test'
const today = new Date(); const today = new Date()
var counter = 0; var counter = 0
const Prometheus = require('prom-client'); const Prometheus = require('prom-client')
const fs = require('file-system'); const fs = require('file-system')
const marked = require('marked'); const marked = require('marked')
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken')
const bodyParser= require('body-parser'); const bodyParser= require('body-parser')
const secret = 'wowmuchsecretveryhiddenwow'; const secret = 'wowmuchsecretveryhiddenwow'
const successUrl = 'http://localhost:3002/yay.html'; const successUrl = 'yay.html'
const failureUrl = 'http://localhost:3002/nay.html'; const failureUrl = 'nay.html'
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser')
const os = require('os')
app.use(cookieParser());
app.use(cookieParser())
// const morgan = require('morgan');
app.use(express.static('html'))
// const morgan = require('morgan')
// // use morgan to log requests to the console // // use morgan to log requests to the console
// app.use(morgan('dev')); // app.use(morgan('dev'))
// global controller // global controller
// app.get('/*',function(req,res,next){ // app.get('/*',function(req,res,next){
// res.header.token = 'sample-token'; // res.header.token = 'sample-token'
// next(); // http://expressjs.com/guide.html#passing-route control // next() // http://expressjs.com/guide.html#passing-route control
// }); // })
// a middleware with no mount path; gets executed for every request to the app // a middleware with no mount path gets executed for every request to the app
// app.use(function(req, res, next) { // app.use(function(req, res, next) {
// res.setHeader('charset', 'utf-8') // res.setHeader('charset', 'utf-8')
// next(); // next()
// }); // })
// setting CORS headers // setting CORS headers
app.all('/', function(req, res, next) { app.all('/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Headers", "X-Requested-With")
next() next()
}); })
// database connection (with retries) // database connection (with retries)
const options = { const options = {
@ -65,20 +68,20 @@ const connectWithRetry = () => {
const libCounter = new Prometheus.Counter({ const libCounter = new Prometheus.Counter({
name: 'lib_invocation_count', name: 'lib_invocation_count',
help: 'A simple counter for app access during runtime created with prometheus nodejs library' help: 'A simple counter for app access during runtime created with prometheus nodejs library'
}); })
const libUptime = new Prometheus.Counter({ const libUptime = new Prometheus.Counter({
name: 'lib_upTime', name: 'lib_upTime',
help: 'uptime A counter of the application\'s uptime in seconds created with prometheus nodejs library.' help: 'uptime A counter of the application\'s uptime in seconds created with prometheus nodejs library.'
}); })
console.log('mongousr: ', process.env.mongousr); console.log('mongousr: ', process.env.mongousr)
console.log('mongopwd: ', process.env.mongopwd); console.log('mongopwd: ', process.env.mongopwd)
// Prometheus Default Metrics collector // Prometheus Default Metrics collector
const collectDefaultMetrics = Prometheus.collectDefaultMetrics; const collectDefaultMetrics = Prometheus.collectDefaultMetrics
// Probe every 5th second. // Probe every 5th second.
collectDefaultMetrics({ timeout: 5000 }); collectDefaultMetrics({ timeout: 5000 })
// new schema model object based on the structure of what I want to put on MongoDB collection // new schema model object based on the structure of what I want to put on MongoDB collection
var testSchema = new Schema({ var testSchema = new Schema({
@ -87,79 +90,81 @@ var testSchema = new Schema({
} }
},{ },{
collection: 'test' collection: 'test'
}); })
// new object that will hold the data using model structure made above // new object that will hold the data using model structure made above
var thingies = mongoose.model('thingieName', testSchema); var thingies = mongoose.model('thingieName', testSchema)
// Default message for testing // Default message for testing
app.get('/', (req, res, next)=>{ app.get('/', (req, res, next)=>{
res.json([{message:'yes, your nodejs app is really running'}]); res.json([{message:'yes, your nodejs app is really running'}])
// res.send('Oh hay' + '\n'); // res.send('Oh hay' + '\n')
counter++; // for prometheus invocation_count metric counter++ // for prometheus invocation_count metric
libCounter.inc(); // for prometheus lib_invocation_count metric libCounter.inc() // for prometheus lib_invocation_count metric
console.log('Hello, I\'m inside endpoint \'/\''); console.log('Hello, I\'m inside endpoint \'/\'')
console.log('HTTP headers below:'); console.log('HTTP headers below:')
console.log(req.headers); console.log(req.headers)
console.log('Cookies: ', req.cookies); console.log('Cookies: ', req.cookies)
console.log('Cookies: ', res.cookies); console.log('Cookies: ', res.cookies)
next(); console.log('\x1b[35m', 'HOSTNAME below:')
}); console.log(os.hostname())
next()
})
// cookie experiments endpoint // cookie experiments endpoint
app.get('/cookie', function(req, res, next) { app.get('/cookie', function(req, res, next) {
// res.cookie('cookiename', 'cookievalue'); // res.cookie('cookiename', 'cookievalue')
// res.setHeader('Set-Cookie', 'cookiename=cookievalue; HttpOnly'); // res.setHeader('Set-Cookie', 'cookiename=cookievalue HttpOnly')
// res.cookie('foo3', 'bar3', { maxAge: 900000, httpOnly: true }); // res.cookie('foo3', 'bar3', { maxAge: 900000, httpOnly: true })
res.json({message: 'I am inside endpoint /cookie'}); res.json({message: 'I am inside endpoint /cookie'})
res.json(JSON.stringify(req.headers)); res.json(JSON.stringify(req.headers))
res.end(); res.end()
console.log('\x1b[35m', 'Cookies: ', req.cookies); console.log('\x1b[35m', 'Cookies: ', req.cookies)
console.log('\x1b[35m', 'req.cookies.token below:'); console.log('\x1b[35m', 'req.cookies.token below:')
console.log(req.cookies.token); console.log(req.cookies.token)
}); })
// Clear cookies // Clear cookies
app.get('/clear', function(req, res) { app.get('/clear', function(req, res) {
res.clearCookie('token'); res.clearCookie('token')
res.clearCookie('cookiename'); res.clearCookie('cookiename')
res.clearCookie('Authorization'); res.clearCookie('Authorization')
res.clearCookie('foo3'); res.clearCookie('foo3')
console.log(req.cookies); console.log(req.cookies)
res.status(200).send('Cookies cleared'); res.status(200).send('Cookies cleared')
}) })
// Test endpoint for md files rendering // Test endpoint for md files rendering
app.get('/test', function(req, res) { app.get('/test', function(req, res) {
var path = '/app/README.md'; var path = '/app/README.md'
var file = fs.readFileSync(path, 'utf8'); var file = fs.readFileSync(path, 'utf8')
res.send(marked(file.toString())); res.send(marked(file.toString()))
}); })
// Prometheus metrics endpoint - Library // Prometheus metrics endpoint - Library
app.get('/metrics', function(req, res){ app.get('/metrics', function(req, res){
libUptime.inc(Math.floor(process.uptime())); libUptime.inc(Math.floor(process.uptime()))
res.set('Content-Type', Prometheus.register.contentType) res.set('Content-Type', Prometheus.register.contentType)
res.end(Prometheus.register.metrics()) res.end(Prometheus.register.metrics())
libUptime.reset(); libUptime.reset()
}); })
// Prometheus metrics endpoint - Handmade // Prometheus metrics endpoint - Handmade
app.get('/metrics2', function(req, res){ app.get('/metrics2', function(req, res){
var now = new Date(); var now = new Date()
var passedTime = now - today; var passedTime = now - today
res.writeHead(200, {'Content-Type':'text/plain'}); res.writeHead(200, {'Content-Type':'text/plain'})
res.write('# HELP uptime A counter of the application\'s uptime in millisenconds.' + '\n'); res.write('# HELP uptime A counter of the application\'s uptime in millisenconds.' + '\n')
res.write('# TYPE uptime counter' + '\n'); res.write('# TYPE uptime counter' + '\n')
res.write('uptime ' + passedTime + '\n'); res.write('uptime ' + passedTime + '\n')
res.write('# HELP invocation_count A simple counter for app access during runtime' + '\n'); res.write('# HELP invocation_count A simple counter for app access during runtime' + '\n')
res.write('# TYPE invocation_count counter'+ '\n'); res.write('# TYPE invocation_count counter'+ '\n')
res.write('invocation_count ' + counter + '\n'); res.write('invocation_count ' + counter + '\n')
res.end(); res.end()
}) })
// JWT generation // JWT generation
app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.urlencoded({ extended: false }))
app.post('/token', function(req, res) { app.post('/token', function(req, res) {
@ -169,7 +174,7 @@ app.post('/token', function(req, res) {
subject: 'power#1234', subject: 'power#1234',
issuer: 'http://youcantrustme.io', issuer: 'http://youcantrustme.io',
scope: 'admin' scope: 'admin'
}; }
const claims_user = { const claims_user = {
username: req.body.username, username: req.body.username,
@ -177,158 +182,158 @@ app.post('/token', function(req, res) {
subject: 'normal_user', subject: 'normal_user',
issuer: 'http://youcantrustme.io', issuer: 'http://youcantrustme.io',
scope: 'user' scope: 'user'
}; }
switch(req.body.username) { switch(req.body.username) {
case 'user1': case 'user1':
if (req.body.password === 'pass1') { if (req.body.password === 'pass1') {
let token = jwt.sign(claims_user, secret); let token = jwt.sign(claims_user, secret)
res.cookie('token', token); res.cookie('token', token)
// res.setHeader('Set-Cookie', 'token=' + token + '; HttpOnly'); // res.setHeader('Set-Cookie', 'token=' + token + ' HttpOnly')
// res.setHeader('Set-Cookie', 'Authorization=Bearer ' + token + '; HttpOnly'); // res.setHeader('Set-Cookie', 'Authorization=Bearer ' + token + ' HttpOnly')
console.log('JWT Token: ' + token); console.log('JWT Token: ' + token)
console.log(jwt.decode(token)); console.log(jwt.decode(token))
res.redirect(successUrl); res.redirect(successUrl)
} else { } else {
res.redirect(failureUrl); res.redirect(failureUrl)
} }
break; break
case 'power': case 'power':
if (req.body.password === 'weak') { if (req.body.password === 'weak') {
let token = jwt.sign(claims_power, secret); let token = jwt.sign(claims_power, secret)
res.cookie('token', token); res.cookie('token', token)
// res.setHeader('Set-Cookie', 'token=' + token + '; HttpOnly'); // res.setHeader('Set-Cookie', 'token=' + token + ' HttpOnly')
console.log('JWT Token: ' + token); console.log('JWT Token: ' + token)
console.log(jwt.decode(token)); console.log(jwt.decode(token))
res.redirect(successUrl); res.redirect(successUrl)
} else { } else {
res.redirect(failureUrl); res.redirect(failureUrl)
} }
break; break
default: default:
res.status(500).send('User not found'); res.status(500).send('User not found')
} }
console.log('http headers below:'); console.log('http headers below:')
console.log(req.headers); console.log(req.headers)
}); })
// Restricted route root // Restricted route root
const restrictedRoutes = express.Router(); const restrictedRoutes = express.Router()
app.use('/restricted', restrictedRoutes); app.use('/restricted', restrictedRoutes)
// setting CORS headers // setting CORS headers
restrictedRoutes.all('/', function(req, res, next) { restrictedRoutes.all('/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Headers", "X-Requested-With")
next() next()
}); })
restrictedRoutes.use(function (req, res, next) { restrictedRoutes.use(function (req, res, next) {
// let sentToken = req.headers['token']; // let hostname = os.hostname()
// let sentToken = req.cookies.token; res.setHeader('HOSTNAME', os.hostname())
if (req.cookies.token) { if (req.cookies.token) {
jwt.verify(req.cookies.token, secret, function (err, decoded) { jwt.verify(req.cookies.token, secret, function (err, decoded) {
if (err) { if (err) {
return res.json({ message: 'invalid token' }); res.json({ message: 'invalid token' })
} else { } else {
req.decoded = decoded; req.decoded = decoded
console.log(decoded); console.log(decoded)
console.log(req.decoded['scope']); console.log(req.decoded['scope'])
switch(req.decoded['scope']) { switch(req.decoded['scope']) {
case 'user': case 'user':
res.status(200).json([{message: 'Need ADMIN scope to access this'}]); res.status(200).json([{message: 'Need ADMIN scope to access the good stuff'}])
break; break
case 'admin': case 'admin':
next(); next()
break; break
default: default:
res.status(401).json([{message: 'Not authorized'}]); res.status(401).json([{message: 'Not authorized'}])
} }
} }
}); })
} else { } else {
res.status(500).send({ message: 'no token found' }); res.status(500).json({ message: 'no token found' })
}; }
}); })
// Restricted endpoint
restrictedRoutes.get('/', (req, res) => {
// let successMsg = JSON.stringify({secret:'You have access to restricted contents!'})
res.status(200).json([{secret:'You have access to restricted contents!'}])
// res.status(200).send(successMsg)
console.log(JSON.stringify({secret:'You have access to restricted contents!'}))
})
// // Restricted route root stupid // // Restricted route root stupid
// const restrictedRoutes = express.Router(); // const restrictedRoutes = express.Router()
// app.use('/restricted', restrictedRoutes); // app.use('/restricted', restrictedRoutes)
// restrictedRoutes.use( function(req, res, next){ // restrictedRoutes.use( function(req, res, next){
// let sentToken = req.headers['token']; // let sentToken = req.headers['token']
// console.log('hello there, do not mind me.'); // console.log('hello there, do not mind me.')
// console.log('next line will show the JWT token:'); // console.log('next line will show the JWT token:')
// console.log(sentToken); // console.log(sentToken)
// console.log('okay, so, next line will show the decoded JWT token:'); // console.log('okay, so, next line will show the decoded JWT token:')
// let decodedToken = jwt.decode(sentToken); // let decodedToken = jwt.decode(sentToken)
// console.log(decodedToken); // console.log(decodedToken)
// console.log('yay, so now I am going to verify it and show again the decoded token if successful.'); // console.log('yay, so now I am going to verify it and show again the decoded token if successful.')
// console.log('if NOT successful I will not let you see the secret message'); // console.log('if NOT successful I will not let you see the secret message')
// console.log('here we go...'); // console.log('here we go...')
// let verifiedToken = jwt.verify(sentToken, secret); // let verifiedToken = jwt.verify(sentToken, secret)
// console.log(verifiedToken); // console.log(verifiedToken)
// if (verifiedToken) { // if (verifiedToken) {
// console.log('success! secret message will be shown.'); // console.log('success! secret message will be shown.')
// next(); // next()
// } else { // } else {
// res.status(401).json({message: 'nope, you are not authorized'}); // res.status(401).json({message: 'nope, you are not authorized'})
// } // }
// }); // })
// Restricted endpoint
restrictedRoutes.get('/', (req, res) => {
// let successMsg = JSON.stringify({secret:'You have access to restricted contents!'});
res.status(200).json([{secret:'You have access to restricted contents!'}]);
// res.status(200).send(successMsg);
console.log(JSON.stringify({secret:'You have access to restricted contents!'}));
});
// Restricted route root test (KISS) // Restricted route root test (KISS)
const router = express.Router(); const router = express.Router()
app.use('/api', router); app.use('/api', router)
router.use( function(req, res, next){ router.use( function(req, res, next){
console.log('yo, this should always be called whenever /api or anything inside is called'); console.log('yo, this should always be called whenever /api or anything inside is called')
next(); next()
}); })
// Restricted route endpoint test (KISS) // Restricted route endpoint test (KISS)
router.get('/inside', (req, res) => { router.get('/inside', (req, res) => {
console.log('I am inside /api, hopefully'); console.log('I am inside /api, hopefully')
res.status(200).json({message: 'it worked'}); res.status(200).json({message: 'it worked'})
}) })
// JWT decode test // JWT decode test
app.get('/decode', function(req, res){ app.get('/decode', function(req, res){
let sentToken = req.headers['token']; let sentToken = req.headers['token']
if (sentToken) { if (sentToken) {
var decode = jwt.verify(sentToken, secret); var decode = jwt.verify(sentToken, secret)
console.log(decode); console.log(decode)
res.status(200).send('success'); res.status(200).send('success')
} }
}) })
// Mongo query // Mongo query
app.get('/info', function(req, res){ app.get('/info', function(req, res){
thingies.find({}).then(function (thingies) { thingies.find({}).then(function (thingies) {
res.json(thingies); res.json(thingies)
}); })
}); })
// Mongo insert // Mongo insert
app.post('/info/add/:name', function(req, res){ app.post('/info/add/:name', function(req, res){
var item = {thingies: req.params.name}; var item = {thingies: req.params.name}
var data = new thingies(item); var data = new thingies(item)
data.save(); data.save()
res.send('thingie ' + req.params.name + ' added to database' + '\n'); res.send('thingie ' + req.params.name + ' added to database' + '\n')
}); })
connectWithRetry(); connectWithRetry()
app.listen(3001, () => { app.listen(3001, () => {
console.log('Server running on port 3001'); console.log('Server running on port 3001')
console.log('process.env.PORT: ' + process.env.PORT); console.log('process.env.PORT: ' + process.env.PORT)
}); })

0
nginx/html/nay.html → node/html/nay.html

3
nginx/html/yay.html → node/html/yay.html

@ -16,11 +16,8 @@
} }
</script> </script>
<!DOCTYPE html>
<html> <html>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
</head>
<body onload="getAPI()"> <body onload="getAPI()">
<div> <div>
<h1>SUCCESS</h1> <h1>SUCCESS</h1>
Loading…
Cancel
Save