Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/api-binary-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
node-version: lts/*

- name: Get repository metadata
id: repo
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
node-version: lts/*

- name: Run mock Keycloak
id: idp-run
Expand Down
36 changes: 23 additions & 13 deletions api/launchers/stig-manager.bat
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@
::==============================================================================
:: set STIGMAN_CLASSIFICATION=

::==============================================================================
:: STIGMAN_CLIENT_ADMIN_TIMEOUT
::
:: | Default: "0" | The maximum time (in minutes) a user with admin privileges
:: can be inactive in the web client before discarding their access token and
:: requiring reauthorization. Activity is defined as mouse click, keypress, or
:: scrolling in any tab or window of a same-origin browsing context group. Set
:: to zero to disable idle detection.
::
:: Affects: Client
::==============================================================================
:: set STIGMAN_CLIENT_ADMIN_TIMEOUT=

::==============================================================================
:: STIGMAN_CLIENT_API_BASE
::
Expand All @@ -90,6 +103,16 @@
::==============================================================================
:: set STIGMAN_CLIENT_API_BASE=

::==============================================================================
:: STIGMAN_CLIENT_CONSOLE_MODE
::
:: | Default: "production" | The console mode of the web client, setting to
:: "development" enables console logging which is otherwise disabled
::
:: Affects: Client
::==============================================================================
:: set STIGMAN_CLIENT_CONSOLE_MODE=

::==============================================================================
:: STIGMAN_CLIENT_DIRECTORY
::
Expand Down Expand Up @@ -143,19 +166,6 @@
::==============================================================================
:: set STIGMAN_CLIENT_ID=

::==============================================================================
:: STIGMAN_CLIENT_ADMIN_TIMEOUT
::
:: | Default: "0" | The maximum time (in minutes) a user with admin privileges
:: can be inactive in the web client before discarding their access token and
:: requiring reauthorization. Activity is defined as mouse click, keypress, or
:: scrolling in any tab or window of a same-origin browsing context group. Set
:: to zero to disable idle detection.
::
:: Affects: Client
::==============================================================================
:: set STIGMAN_CLIENT_ADMIN_TIMEOUT=

::==============================================================================
:: STIGMAN_CLIENT_OIDC_PROVIDER
::
Expand Down
36 changes: 23 additions & 13 deletions api/launchers/stig-manager.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,19 @@
#==============================================================================
# export STIGMAN_CLASSIFICATION=

#==============================================================================
# STIGMAN_CLIENT_ADMIN_TIMEOUT
#
# | Default: "0" | The maximum time (in minutes) a user with admin privileges
# can be inactive in the web client before discarding their access token and
# requiring reauthorization. Activity is defined as mouse click, keypress, or
# scrolling in any tab or window of a same-origin browsing context group. Set
# to zero to disable idle detection.
#
# Affects: Client
#==============================================================================
# export STIGMAN_CLIENT_ADMIN_TIMEOUT=

#==============================================================================
# STIGMAN_CLIENT_API_BASE
#
Expand All @@ -89,6 +102,16 @@
#==============================================================================
# export STIGMAN_CLIENT_API_BASE=

#==============================================================================
# STIGMAN_CLIENT_CONSOLE_MODE
#
# | Default: "production" | The console mode of the web client, setting to
# "development" enables console logging which is otherwise disabled
#
# Affects: Client
#==============================================================================
# export STIGMAN_CLIENT_CONSOLE_MODE=

#==============================================================================
# STIGMAN_CLIENT_DIRECTORY
#
Expand Down Expand Up @@ -142,19 +165,6 @@
#==============================================================================
# export STIGMAN_CLIENT_ID=

#==============================================================================
# STIGMAN_CLIENT_ADMIN_TIMEOUT
#
# | Default: "0" | The maximum time (in minutes) a user with admin privileges
# can be inactive in the web client before discarding their access token and
# requiring reauthorization. Activity is defined as mouse click, keypress, or
# scrolling in any tab or window of a same-origin browsing context group. Set
# to zero to disable idle detection.
#
# Affects: Client
#==============================================================================
# export STIGMAN_CLIENT_ADMIN_TIMEOUT=

#==============================================================================
# STIGMAN_CLIENT_OIDC_PROVIDER
#
Expand Down
1 change: 1 addition & 0 deletions api/source/bootstrap/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function getClientEnv(){
`const STIGMAN = {
Env: {
version: "${config.version}",
consoleMode: "${config.client.consoleMode}",
apiBase: "${config.client.apiBase}",
displayAppManagers: ${config.client.displayAppManagers},
stateEvents: ${config.client.stateEvents},
Expand Down
5 changes: 5 additions & 0 deletions api/source/bootstrap/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const logger = require('../utils/logger')

function configureMiddleware(app) {

// Must run before any app.use() call: Express's lazyrouter binds the query
// parser at the moment the first middleware is registered and ignores
// later changes.
app.set('query parser', 'simple')

const middlewareConfigFunctions = [
configureMulter,
configureExpress,
Expand Down
4 changes: 2 additions & 2 deletions api/source/controllers/Asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,8 @@ function getCollectionIdAndVerifyAccess(request, minimumRole = Security.ROLES.Ma
*/
async function getAssetInfoAndVerifyAccess(request, roleId = Security.ROLES.Manage) {
const assetId = request.params.assetId
const [rows] = await dbUtils.selectCollectionByAssetId(assetId)
const grant = request.userObject.grants[rows[0]?.collectionId]
const row = await dbUtils.selectCollectionByAssetId(assetId)
const grant = request.userObject.grants[row?.collectionId]
// check if user has sufficient access level
if (!grant || grant.roleId < roleId) {
throw new SmError.PrivilegeError("Insufficient access to this asset's collection.")
Expand Down
9 changes: 9 additions & 0 deletions api/source/controllers/Collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ module.exports.createCollection = async function createCollection (req, res, nex
const elevate = req.query.elevate
const body = req.body
if ( elevate || req.userObject.privileges.create_collection ) {
if (elevate && (body.settings !== undefined || body.labels !== undefined || body.metadata !== undefined)) {
throw new SmError.PrivilegeError('Elevated requests cannot set collection settings, labels, or metadata.')
}
if (!hasUniqueGrants(body.grants)) {
throw new SmError.UnprocessableError('Duplicate user or user group in grant array')
}
Expand Down Expand Up @@ -266,6 +269,9 @@ module.exports.replaceCollection = async function replaceCollection (req, res, n
const projection = req.query.projection
const body = req.body

if (elevate && (body.settings !== undefined || body.labels !== undefined || body.metadata !== undefined)) {
throw new SmError.PrivilegeError('Elevated requests cannot set collection settings, labels, or metadata.')
}
if (!hasUniqueGrants(body.grants)) {
throw new SmError.UnprocessableError('Duplicate user in grant array')
}
Expand Down Expand Up @@ -306,6 +312,9 @@ module.exports.updateCollection = async function updateCollection (req, res, nex
const {collectionId, grant} = await getCollectionInfoAndCheckPermission(req, Security.ROLES.Manage, true)
const projection = req.query.projection
const body = req.body
if (elevate && (body.settings !== undefined || body.labels !== undefined || body.metadata !== undefined)) {
throw new SmError.PrivilegeError('Elevated requests cannot set collection settings, labels, or metadata.')
}
if (body.grants) {
if (!hasUniqueGrants(body.grants)) {
throw new SmError.UnprocessableError('Duplicate user in grant array')
Expand Down
28 changes: 19 additions & 9 deletions api/source/controllers/Review.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ module.exports.postReviewsByAsset = async function postReviewsByAsset (req, res,
const assetId = req.params.assetId
const reviews = req.body

// check assetId exists and is enabled
const assetExists = await AssetService.doesAssetExist(assetId)
if (!assetExists) {
// check assetId exists, is enabled, and belongs to the collection in the URL path
const assetRow = await dbUtils.selectCollectionByAssetId(assetId)
if (!assetRow || assetRow.collectionId.toString() !== collectionId) {
throw new SmError.PrivilegeError()
}

Expand Down Expand Up @@ -162,9 +162,10 @@ module.exports.putReviewByAssetRule = async function (req, res, next) {
const {assetId, ruleId} = {...req.params}
const review = {...req.body, ruleId}
const projections = req.query.projection
// check assetId exists and is enabled
const assetExists = await AssetService.doesAssetExist(assetId)
if (!assetExists) {

// check assetId exists, is enabled, and belongs to the collection in the URL path
const assetRow = await dbUtils.selectCollectionByAssetId(assetId)
if (!assetRow || assetRow.collectionId.toString() !== collectionId) {
throw new SmError.PrivilegeError()
}

Expand All @@ -181,7 +182,7 @@ module.exports.putReviewByAssetRule = async function (req, res, next) {
}
const rows = await ReviewService.getReviews({
projections,
filter: {assetId, ruleId},
filter: {collectionId, assetId, ruleId},
grant,
userObject: req.userObject
})
Expand All @@ -199,8 +200,17 @@ module.exports.patchReviewByAssetRule = async function (req, res, next) {
}
const {collectionId, grant} = await Collection.getCollectionInfoAndCheckPermission(req, Security.ROLES.Restricted)
const {assetId, ruleId} = {...req.params}

// check assetId exists, is enabled, and belongs to the collection in the URL path —
// must run before the pre-write existence read so a foreign-collection asset
// cannot satisfy the "review must exist" gate and reveal review state via 404 vs 403
const assetRow = await dbUtils.selectCollectionByAssetId(assetId)
if (!assetRow || assetRow.collectionId.toString() !== collectionId) {
throw new SmError.PrivilegeError()
}

const currentReviews = await ReviewService.getReviews({
filter: {assetId, ruleId},
filter: {collectionId, assetId, ruleId},
grant,
userObject: req.userObject
})
Expand All @@ -222,7 +232,7 @@ module.exports.patchReviewByAssetRule = async function (req, res, next) {
}
const rows = await ReviewService.getReviews({
projections,
filter: {assetId, ruleId},
filter: {collectionId, assetId, ruleId},
grant,
userObject: req.userObject
})
Expand Down
Loading
Loading