1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 11:24:35 +00:00

fix: read security code from file + redirect

This commit is contained in:
Saad Jutt
2021-10-14 18:51:32 +05:00
parent 8fb7129f86
commit 4912915a6e
6 changed files with 113 additions and 46 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ sas/
tmp/
build/
.env
security.json

3
security.json.example Normal file
View File

@@ -0,0 +1,3 @@
{
"code": "place security code here"
}

View File

@@ -1,10 +1,16 @@
import path from 'path'
import express from 'express'
import { renderFile } from 'ejs'
import dotenv from 'dotenv'
import { Routes } from './routes'
import { passportMiddleware } from './middleware'
import { getAuthMechanisms } from './utils'
import { AuthMechanism } from './types'
import session from 'express-session'
dotenv.config()
const authMechanisms = getAuthMechanisms()
const app = express()
@@ -16,14 +22,44 @@ app.set('views', path.join(__dirname, './views'))
app.use(express.json({ limit: '50mb' }))
app.use(express.static(path.join(__dirname, '..', 'public')))
const sessionConfig = {
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
cookie: {
secure: false // set this to true on production
}
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sessionConfig.cookie.secure = true // serve secure cookies
}
app.use(session(sessionConfig))
app.get(Routes.Login, (req, res) => {
if (
authMechanisms.length === 1 &&
authMechanisms[0] === AuthMechanism.NoSecurity
) {
res.redirect('/')
} else {
const session: any = req.session
const isAuthenticated = !!session?.passport?.user
if (isAuthenticated) {
res.redirect('/')
} else {
res.render('sasjslogon.html', { authMechanisms })
}
}
})
app.use(passportMiddleware())
const authMechanisms = getAuthMechanisms()
app.get(Routes.Login, (req, res) => {
res.render('sasjslogon.html', { authMechanisms })
})
app.get('/error', (req, res) => res.redirect('/500.html'))
app.get('/unauthorized', (req, res) => res.redirect('/401.html'))
app.get('*', (req, res) => res.status(404).redirect('/404.html'))
// app.get('*', (req, res) => res.status(404).redirect('/404.html'))
export default app

View File

@@ -1,37 +1,21 @@
import path from 'path'
import jwt from 'jsonwebtoken'
import dotenv from 'dotenv'
import express from 'express'
import session from 'express-session'
import passport from 'passport'
import { Strategy } from 'passport-local'
const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2')
import { ensureLoggedIn } from 'connect-ensure-login'
import { readFile } from '@sasjs/utils'
import { AuthMechanism } from './types'
import { getAuthMechanisms } from './utils'
import indexRouter, { Routes } from './routes'
export const passportMiddleware = (): express.Express => {
dotenv.config()
const authMechanisms = getAuthMechanisms()
const middleware = express()
const sessionConfig = {
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
cookie: {
secure: false // set this to true on production
}
}
if (middleware.get('env') === 'production') {
middleware.set('trust proxy', 1) // trust first proxy
sessionConfig.cookie.secure = true // serve secure cookies
}
middleware.use(session(sessionConfig))
setupPassportStrategies(authMechanisms)
middleware.use(passport.initialize())
@@ -49,10 +33,10 @@ export const passportMiddleware = (): express.Express => {
authMechanisms[0] === AuthMechanism.NoSecurity
) {
console.log('Using No Security')
middleware.get('/', indexRouter)
middleware.all('/*', indexRouter)
} else {
middleware.get(
'/',
middleware.all(
'/*',
ensureLoggedIn({ redirectTo: '/SASjsLogon' }),
indexRouter
)
@@ -65,15 +49,18 @@ const setupPassportStrategies = (authMechanisms: string[]) => {
if (authMechanisms.includes(AuthMechanism.Local)) {
console.log('Using Local Authentication')
passport.use(
new Strategy((username: string, password: string, cb: Function) => {
console.log('username', username)
if (username !== 'SaadJutt')
return cb(null, false, { message: 'Incorrect Username' })
new Strategy(async (username: string, code: string, cb: Function) => {
const content = await readFile(
path.join(__dirname, '..', 'security.json')
)
const { code: securityCode } = JSON.parse(content)
if (securityCode !== code)
return cb(null, false, { message: 'Incorrect Security Code' })
const user = {
id: 'SOMEID',
username: username,
displayName: 'displayName'
displayName: username
}
return cb(null, user)
})
@@ -95,11 +82,20 @@ const setupPassportStrategies = (authMechanisms: string[]) => {
profile: any,
done: any
) {
// currently we can't find a way to exchange access token by user info (see userProfile implementation), so
// you will need a jwt-package like https://github.com/auth0/node-jsonwebtoken to decode id_token and get waad profile
var waadProfile = profile || jwt.decode(params.id_token)
const decoded = jwt.decode(params.id_token)
done(null, { id: waadProfile.upn })
const user = {
id: 'ID',
username: 'username',
displayName: 'display name'
}
if (decoded && typeof decoded === 'object') {
user.id = decoded.oid
user.username = decoded.unique_name
user.displayName = decoded.name
}
done(null, user)
}
)
)
@@ -127,20 +123,30 @@ const setupPassportRoutes = (
app.get(
Routes.AzureSignInRedirect,
passport.authenticate('azure_ad_oauth2', {
successRedirect: '/',
failureRedirect: Routes.Login,
failureMessage: true
})
}),
(req, res) => {
const session: any = req.session
const returnTo = session.returnTo ?? '/'
session.returnTo = undefined
res.redirect(returnTo)
}
)
}
if (authMechanisms.includes(AuthMechanism.Local)) {
app.post(
Routes.LocalSignIn,
passport.authenticate(['local'], {
successRedirect: '/',
passport.authenticate('local', {
failureRedirect: Routes.Login,
failureMessage: true
})
}),
(req, res) => {
const session: any = req.session
const returnTo = session.returnTo ?? '/'
session.returnTo = undefined
res.redirect(returnTo)
}
)
}
}

View File

@@ -1,23 +1,40 @@
import express from 'express'
import { processSas, createFileTree, getTreeExample } from '../controllers'
import { ExecutionResult, isRequestQuery, isFileTree } from '../types'
import {
ExecutionResult,
isRequestQuery,
isFileTree,
AuthMechanism
} from '../types'
import { getAuthMechanisms } from '../utils'
const router = express.Router()
const header = (user: any) => {
const authMechanisms = getAuthMechanisms()
if (
authMechanisms.length === 1 &&
authMechanisms[0] === AuthMechanism.NoSecurity
)
return '<div><p>No Security applied</p></div>'
return `<div><p>Logged in as ${user.username} <a href="/signout" role="button">Logout</a></p></div>`
}
router.get('/', async (req, res) => {
const query = req.query
if (!isRequestQuery(query)) {
res.send('Welcome to @sasjs/server API')
res.send(`${header(req.user)}Welcome to @sasjs/server API`)
return
}
const result: ExecutionResult = await processSas(query)
res.send(`<b>Executed!</b><br>
res.send(`${header(req.user)}<b>Executed!</b><br>
<p>Log is located:</p> ${result.logPath}<br>
<p>Log:</p> <textarea style="width: 100%; height: 100%">${result.log}</textarea>`)
<p>Log:</p> <textarea style="width: 100%; height: 100%">${
result.log
}</textarea>`)
})
router.post('/deploy', async (req, res) => {

View File

@@ -27,7 +27,11 @@
<form action="/signin-with-local" method="post">
<input type="text" name="username" placeholder="Username" />
<input type="password" name="password" placeholder="Password" />
<input
type="text"
name="password"
placeholder="Security Code"
/>
<button type="submit" class="contrast">Sign in</button>
</form>
</div>