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
1 change: 1 addition & 0 deletions portals/api-portal/configs/config-template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ subscriber = "ap_subscriber"
[api_portal.organization]
handle = "default" # URL slug: /{handle}/views/{viewName}
display_name = "Default" # Used only when first seeding the organization
portal_id = "portal_id" # Unique portal identifier within this org
auto_create_subscription_plans = true # Auto-create Bronze/Silver/Gold/Unlimited/AsyncUnlimited
# default_name = "default" # DEPRECATED alias for `handle` — rename it

Expand Down
1 change: 1 addition & 0 deletions portals/api-portal/configs/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ subscriber = "ap_subscriber"
[api_portal.organization]
handle = '{{ env "APIP_AP_ORGANIZATION_HANDLE" "default" }}'
display_name = '{{ env "APIP_AP_ORGANIZATION_DISPLAY_NAME" "Default" }}'
portal_id = '{{ env "APIP_AP_ORGANIZATION_PORTAL_ID" "portal_id" }}'
314 changes: 191 additions & 123 deletions portals/api-portal/database/schema.postgres.sql

Large diffs are not rendered by default.

310 changes: 189 additions & 121 deletions portals/api-portal/database/schema.sqlite.sql

Large diffs are not rendered by default.

310 changes: 189 additions & 121 deletions portals/api-portal/database/schema.sqlserver.sql

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions portals/api-portal/it/test-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ session_secret = '{{ env "APIP_AP_SECURITY_SESSION_SECRET" }}'
# login-time organization-mismatch rejection.
handle = '{{ env "APIP_AP_ORGANIZATION_HANDLE" "default" }}'
display_name = '{{ env "APIP_AP_ORGANIZATION_DISPLAY_NAME" "Default" }}'
portal_id = '{{ env "APIP_AP_ORGANIZATION_PORTAL_ID" "portal_id" }}'
auto_create_subscription_plans = true

# Most of the suite authorizes against the dp:* scopes the Platform API sidecar mints
Expand Down
8 changes: 7 additions & 1 deletion portals/api-portal/src/config/configDefaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ const DEFAULTS = {
// Which role name, as it appears in the token's roles claim, grants each
// of the portal's two access tiers. Was auth.idp.roles, despite being read in
// local mode too (authController.js's login). A third tier, superAdmin, used
// to gate the earlier devportal's /portal pages; those are not served here, so
// to gate the earlier api portal's /portal pages; those are not served here, so
// it guarded nothing and was removed.
portalRoles: {
admin: 'admin',
Expand Down Expand Up @@ -291,6 +291,12 @@ const DEFAULTS = {
// default_name keeps working. Resolved (with a warning) in configLoader.js.
defaultName: '',
autoCreateSubscriptionPlans: true,
// API Portal identifier this portal instance is pinned to.
// Resolved by the config.toml template before reaching this default.
// Set APIP_AP_ORGANIZATION_PORTAL_ID for cloud/K8s deployments, or override
// organization.portal_id in a local config file for on-premise. When neither
// is set the template resolves to 'portal_id'.
portalId: '',
},
// Which artifact types this portal serves. An allowlist: a type not listed here
// gets no nav entry, no landing-page section, and 404s on its routes. Any
Expand Down
31 changes: 31 additions & 0 deletions portals/api-portal/src/config/configLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,37 @@ function resolveOrganizationConfig(cfg, tomlOrg) {

resolveOrganizationConfig(config, interpolatedTomlConfig.organization);

/**
* Validates the portal identifier this instance will be pinned to, and fails
* closed when it is empty or malformed.
* Design mode renders from disk and uses no database, so portal_id is unused
* and validation is skipped.
*/
function resolvePortalIdConfig(cfg) {
if (cfg.designMode?.enabled) return;

const portalId = cfg.organization?.portalId;
const trimmed = typeof portalId === 'string' ? portalId.trim() : '';

if (!trimmed) {
process.stderr.write(
'[FATAL] organization.portal_id is not configured or resolves to an empty string. ' +
'Set APIP_AP_ORGANIZATION_PORTAL_ID in your environment, or organization.portal_id ' +
"in configs/config.toml, e.g. portal_id = '{{ env \"APIP_AP_ORGANIZATION_PORTAL_ID\" \"portal_id\" }}'.\n"
);
process.exit(1);
}
if (/\s/.test(portalId)) {
process.stderr.write(
'[FATAL] organization.portal_id contains whitespace. API Portal identifiers ' +
'must not contain spaces or tabs.\n'
);
process.exit(1);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

resolvePortalIdConfig(config);

/**
* Refuses to start when auth.mode = "idp" is selected without the endpoints OIDC login
* actually needs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ const generateOAuthKeys = async (req, res) => {
if (!keyMapping || !keyMapping.km_uuid) {
throw new CustomError(404, 'Key mapping not found or missing key manager reference');
}
const kmRecord = await kmDao.get(keyMapping.km_uuid);
const kmRecord = await kmDao.get(orgId, keyMapping.km_uuid);
if (!kmRecord) {
throw new CustomError(404, 'Key manager not found');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const loadApplicationData = async (req, orgName, applicationHandle, viewName) =>
for (const mapping of localMappings) {
if (mapping.as_client_id && mapping.km_uuid) {
try {
const km = await kmDao.get(mapping.km_uuid);
const km = await kmDao.get(orgId, mapping.km_uuid);
keyList.push({
keyManager: km.handle,
consumerKey: mapping.as_client_id,
Expand Down
2 changes: 2 additions & 0 deletions portals/api-portal/src/controllers/authController.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const handleCallback = async (req, res, next) => {
}
returnTo = returnTo || `${constants.ROUTE.BASE_PATH}/${req.params.orgName}`;
delete req.session.returnTo;
req.session.portalId = orgContext.getPortalId();
logUserAction('USER_LOGIN', req, { orgName: req.params.orgName });
req.session.save((saveErr) => {
if (saveErr) {
Expand Down Expand Up @@ -402,6 +403,7 @@ const handleLocalLogin = async (req, res) => {
logger.error('Platform-auth login session error', { error: loginErr.message, stack: loginErr.stack });
return res.redirect(`${baseUrl}/login?error=Login+failed%2C+please+try+again`);
}
req.session.portalId = orgContext.getPortalId();
logUserAction('USER_LOGIN', req, { orgName, isLocalAuth: true });
res.set('Cache-Control', 'no-store');
const redirectTo = returnTo || baseUrl;
Expand Down
Loading
Loading