-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(store-api): Improve project structure MVC. Add middleware for JW…
…T validation and OpenFGA permission check.
- Loading branch information
Showing
12 changed files
with
265 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,11 @@ | |
"name": "store-openfga-api", | ||
"description": "An OAuth 2.0 API protected by OpenFGA for fine-grained authorization.", | ||
"author": "Martin Besozzi <[email protected]>)", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"license": "MIT", | ||
"main": "server.js", | ||
"scripts": { | ||
"start": "nodemon server.js", | ||
"start": "nodemon src/server.js", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"dependencies": { | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
jwksUri: process.env.OIDC_PROVIDER_JWKS_URI || "http://localhost:8081/realms/master/protocol/openid-connect/certs", | ||
audience: process.env.OIDC_PROVIDER_AUDIENCE || "account", | ||
issuer: process.env.OIDC_PROVIDER_DOMAIN || "http://localhost:8081/realms/master" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
apiScheme: process.env.OPENFGA_API_SCHEME || "http", | ||
apiHost: process.env.OPENFGA_API_HOST || "openfga:8080" | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const fga = require('../middlewares/openfga'); | ||
|
||
const productsService = require('../services/products.service'); | ||
|
||
const get = async function(req, res){ | ||
console.log(`[Store API] Getting product id: ${req.params.id}`); | ||
res.send(productsService.get(req.params.id)); | ||
} | ||
|
||
const getAll = async function(req, res){ | ||
console.log('[Store API] Getting products'); | ||
res.send(productsService.getAll()); | ||
} | ||
|
||
const publish = async function(req, res){ | ||
console.log(`[Store API] Publishing product id: ${req.params.id}`); | ||
res.send(productsService.publish(req.params.id)); | ||
} | ||
|
||
module.exports = { | ||
get, | ||
getAll, | ||
publish | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
module.exports = { | ||
Products: [ | ||
{ | ||
id: 1, | ||
name: 'Glasses Ray Ban', | ||
category: "pre-sale", | ||
description: 'Ray-Ban Black Original Wayfarer Classic Sunglasses', | ||
url : "https://source.unsplash.com/K62u25Jk6vo/600x300", | ||
details : "Brand <b>Ray-Ban</b> <br> Model Name Stories <br> Style Stories<br> Color Shiny Blue/Dark Blue Polarized <br> Age Range (Description) Adult", | ||
status : "publish" | ||
}, | ||
{ | ||
id: 2, | ||
name: 'Apple watch', | ||
category: "pre-sale", | ||
description: 'Apple Watch Series 3 42MM Special Features', | ||
url : "https://source.unsplash.com/2cFZ_FB08UM/600x300", | ||
details : "Brand <b>Apple</b> <br> Model Name Apple Watch Series <br> Style GPS <br> Special Feature Activity Tracker, Heart Rate Monitor, Sleep Monitor, Blood Oxygen", | ||
status : "publish" | ||
}, | ||
{ | ||
id: 3, | ||
name: 'Headphones Bose', | ||
category: "pre-sale", | ||
description: 'Bose Noise Cancelling Wireless Headphones 700', | ||
url : "https://source.unsplash.com/vISNAATFXlE/600x300", | ||
details: "Brand <b>Bose</b> <br> Audio Model Name <br> Performance ANC HeadphonesColor<br>Technology Bluetooth 5.0", | ||
status: "published" | ||
}, | ||
{ | ||
id: 4, | ||
name: 'Nikon Camera', | ||
category: "pre-sale", | ||
description: "Nikon Camera Z50 Two Lens Coolpix B500", | ||
url : "https://source.unsplash.com/dcgB3CgidlU/600x300", | ||
status : "publish", | ||
details: "Brand <b>Nikon</b> <br>Model Name Nikon Coolpix B500 <br>Form Factor Point and Shoot <br>Effective Still Resolution 16 MP", | ||
status : "published" | ||
}, | ||
{ | ||
id: 5, | ||
name: 'Chanel N°5 Perfume', | ||
category: "pre-sale", | ||
description: 'Ulric De Varens Gold Issime Pour Elle 75ml Estilo Chanel Nº5.', | ||
url : "https://source.unsplash.com/potCPE_Cw8A/600x300", | ||
details : "Brand <b>CHANEL<b> <br>Item Form Spray <br>Item Volume 3.4 Fluid Ounces <br> Age Range (Description)Adult", | ||
status : "published" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
const jwt = require("express-jwt"); | ||
const { decode } = require('jsonwebtoken'); | ||
const config = require("../config/jwt.config.js"); | ||
const jwksRsa = require("jwks-rsa"); | ||
|
||
validateToken = jwt({ | ||
secret: jwksRsa.expressJwtSecret({ | ||
cache: true, | ||
rateLimit: true, | ||
jwksRequestsPerMinute: 5, | ||
jwksUri: config.jwksUri | ||
}), | ||
audience: config.audience, | ||
issuer: config.issuer, | ||
algorithms: ["RS256"] | ||
}); | ||
|
||
decodeToken = (req, res, next) => { | ||
const auth = req.get('Authorization'); | ||
const { sub } = decode(auth.split(' ')[1]); | ||
req.userId = sub; | ||
return next(); | ||
}; | ||
|
||
|
||
module.exports = { | ||
validateToken, | ||
decodeToken | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
const { OpenFgaApi } = require("@openfga/sdk"); | ||
|
||
const config = require("../config/openfga.config.js"); | ||
const { all } = require("../routes/products.route.js"); | ||
|
||
const fgaClient = new OpenFgaApi({ | ||
apiScheme: config.apiScheme, | ||
apiHost: config.apiHost | ||
}); | ||
|
||
const discoverStore = async () => { | ||
try { | ||
const { stores } = await fgaClient.listStores(); | ||
for (const store of stores) { | ||
console.log(`[Store API] Store found name: ${store.name} id: ${store.id}`); | ||
fgaClient.storeId = store.id; | ||
} | ||
return fgaClient; | ||
} | ||
catch(e){ | ||
throw new Error('OpenFGA is not initialized properly') | ||
} | ||
} | ||
|
||
const getClient = async () => { | ||
return (fgaClient.storeId) ? fgaClient : await discoverStore(); | ||
} | ||
|
||
const checkTuple = async function (user, relation, object) { | ||
console.log(`[Store API] Check tuple (user: '${user}', rel: '${relation}', obj: '${object}')`); | ||
try { | ||
let client = await getClient(); | ||
let { allowed } = await client.check({ | ||
tuple_key: { | ||
user: user, | ||
relation: relation, | ||
object: object | ||
} | ||
}); | ||
console.log(`[Store API] Check tuple for user: ${user} isAllowed: ${allowed}`); | ||
return allowed; | ||
} catch ( e ) { | ||
console.log(e); | ||
return false; | ||
} | ||
} | ||
|
||
const userHasRole = async (userId, roleName) => { | ||
return await checkTuple( `user:${userId}`, "assignee", `role:${roleName}`); | ||
} | ||
|
||
const checkUserHasRole = (roleName) => { | ||
return async (req, res, next) => { | ||
let allowed = await userHasRole(req.userId, roleName) | ||
|
||
if(allowed) { | ||
next(); | ||
} | ||
else { | ||
res.status(403).send(); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
module.exports = { | ||
checkUserHasRole | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const express = require('express'); | ||
const products = require('./products.route'); | ||
|
||
const router = express.Router(); | ||
|
||
router.use('/api/products', products); | ||
|
||
router.get('/', (req, res) => res.send('API version 1.0.0')); | ||
|
||
module.exports = router; |
Oops, something went wrong.