Add API tokens (#838)

* protects db endpoints with auth data, but will require ui updates to function properly

* adds an Authorization header with bearer token to all api/db/* request endpoints

* force login if token doesn't exist

* remove debug code
This commit is contained in:
Ryan 2021-03-11 19:13:38 -05:00 committed by GitHub
parent 60b75b5f5e
commit 7848b6c966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 8230 additions and 34 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
# This directory is fetched during first build and is present in this directory
subprojects/freeDiameter
subprojects/usrsctp
webui/.next

8214
webui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
"express-restify-mongoose": "^4.3.0",
"express-session": "^1.15.2",
"immutable": "^3.8.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.10",
"lusca": "^1.6.0",
"method-override": "^2.3.9",
@ -27,6 +28,7 @@
"nprogress": "^0.2.0",
"open-color": "^1.6.3",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"passport-local-mongoose": "^4.5.0",
"prop-types": "^15.6.2",

View File

@ -21,6 +21,7 @@ const MongoStore = require('connect-mongo')(session);
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const csrf = require('lusca').csrf();
const secret = process.env.SECRET_KEY || 'change-me';

View File

@ -3,6 +3,9 @@ const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET_KEY || 'change-me';
router.get('/csrf', (req, res) => {
return res.json({csrfToken: res.locals._csrf});
})
@ -14,6 +17,9 @@ router.get('/session', (req, res) => {
}
if (req.user) {
session.user = req.user
const body = { '_id': req.user._id, 'username': req.user.username, 'roles':req.user.roles };
const token = jwt.sign({ user: body }, secret);
session.authToken = token
}
return res.json(session)

View File

@ -4,7 +4,28 @@ const db = require('./db')
const router = express.Router();
const secret = process.env.JWT_SECRET_KEY || 'change-me';
const passport = require('passport');
const JWTstrategy = require('passport-jwt').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
passport.use(
new JWTstrategy(
{
secretOrKey: secret,
jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('bearer')
},
async (token, done) => {
try {
return done(null, token.user);
} catch (error) {
done(error);
}
}
)
);
router.use('/auth', auth);
router.use('/db', db);
router.use('/db', passport.authenticate('jwt', { session: false }), db);
module.exports = router;

View File

@ -12,7 +12,7 @@ export default (Component) => class extends React.Component {
const sessionData = await session.getSession();
let isLoggedIn = false;
if (sessionData.user && sessionData.user.username) {
if (sessionData.user && sessionData.user.username && sessionData.authToken) {
isLoggedIn = true;
}

View File

@ -31,6 +31,9 @@ export default class Session {
if (req.user) {
this.session.user = req.user
}
if (req.authToken) {
this.session.authToken = req.authToken;
}
} else {
// If running on client, attempt to load session from localStorage
this.session = this.getLocalStore('session')

View File

@ -3,10 +3,14 @@ import { all, takeEvery, put, call, take, fork } from 'redux-saga/effects';
import { CRUD } from './actions';
import Session from 'modules/auth/session';
const crudApi = (method, url, csrf, { params, data } = {} ) => {
const crudApi = (method, url, csrf, authToken, { params, data } = {} ) => {
let headers = { 'X-CSRF-TOKEN': csrf }
if (authToken) {
headers['Authorization'] = "Bearer " + authToken
}
return axios({
baseURL: '/api/db',
headers: { 'X-CSRF-TOKEN': csrf },
headers: headers,
method,
url,
params,
@ -25,7 +29,8 @@ function* crudEntity(action) {
try {
const sessionData = new Session();
const csrf = ((sessionData || {}).session || {}).csrfToken;
const response = yield call(crudApi, method, url, csrf, { params, data })
const authToken = ((sessionData || {}).session || {}).authToken;
const response = yield call(crudApi, method, url, csrf, authToken, { params, data })
yield put({ meta, type: success, payload: response })
} catch (error) {
yield put({ meta, type: failure, payload: error, error: true })