diff --git a/server/routers/olm/error.ts b/server/routers/olm/error.ts index 289e7219..6ea209ce 100644 --- a/server/routers/olm/error.ts +++ b/server/routers/olm/error.ts @@ -3,7 +3,7 @@ import { sendToClient } from "#dynamic/routers/ws"; export const OlmErrorCodes = { OLM_NOT_FOUND: { code: "OLM_NOT_FOUND", - message: "The requested OLM session could not be found." + message: "The specified device could not be found." }, CLIENT_ID_NOT_FOUND: { code: "CLIENT_ID_NOT_FOUND", @@ -15,15 +15,18 @@ export const OlmErrorCodes = { }, CLIENT_BLOCKED: { code: "CLIENT_BLOCKED", - message: "This client has been blocked and cannot connect." + message: + "This client has been blocked in this organization and cannot connect. Please contact your administrator." }, CLIENT_PENDING: { code: "CLIENT_PENDING", - message: "This client is pending approval and cannot connect yet." + message: + "This client is pending approval and cannot connect yet. Please contact your administrator." }, ORG_NOT_FOUND: { code: "ORG_NOT_FOUND", - message: "The organization could not be found." + message: + "The organization could not be found. Please select a valid organization." }, USER_ID_NOT_FOUND: { code: "USER_ID_NOT_FOUND", @@ -31,23 +34,42 @@ export const OlmErrorCodes = { }, INVALID_USER_SESSION: { code: "INVALID_USER_SESSION", - message: "Your user session is invalid or has expired." + message: + "Your user session is invalid or has expired. Please log in again." }, USER_ID_MISMATCH: { code: "USER_ID_MISMATCH", message: "The provided user ID does not match the session." }, - ACCESS_POLICY_DENIED: { - code: "ACCESS_POLICY_DENIED", - message: "Access denied due to policy restrictions." + ORG_ACCESS_POLICY_DENIED: { + code: "ORG_ACCESS_POLICY_DENIED", + message: + "Access to this organization has been denied by policy. Please contact your administrator." + }, + ORG_ACCESS_POLICY_PASSWORD_EXPIRED: { + code: "ORG_ACCESS_POLICY_PASSWORD_EXPIRED", + message: + "Access to this organization has been denied because your password has expired. Please visit this organization's dashboard to update your password." + }, + ORG_ACCESS_POLICY_SESSION_EXPIRED: { + code: "ORG_ACCESS_POLICY_SESSION_EXPIRED", + message: + "Access to this organization has been denied because your session has expired. Please log in again to refresh the session." + }, + ORG_ACCESS_POLICY_2FA_REQUIRED: { + code: "ORG_ACCESS_POLICY_2FA_REQUIRED", + message: + "Access to this organization requires two-factor authentication. Please visit this organization's dashboard to enable two-factor authentication." }, TERMINATED_REKEYED: { code: "TERMINATED_REKEYED", - message: "This session was terminated because encryption keys were regenerated." + message: + "This session was terminated because encryption keys were regenerated." }, TERMINATED_ORG_DELETED: { code: "TERMINATED_ORG_DELETED", - message: "This session was terminated because the organization was deleted." + message: + "This session was terminated because the organization was deleted." }, TERMINATED_INACTIVITY: { code: "TERMINATED_INACTIVITY", @@ -69,7 +91,7 @@ export const OlmErrorCodes = { // Helper function to send registration error export async function sendOlmError( - error: typeof OlmErrorCodes[keyof typeof OlmErrorCodes], + error: (typeof OlmErrorCodes)[keyof typeof OlmErrorCodes], olmId: string ) { sendToClient(olmId, { diff --git a/server/routers/olm/handleOlmRegisterMessage.ts b/server/routers/olm/handleOlmRegisterMessage.ts index a8c1327d..c8a8d3f7 100644 --- a/server/routers/olm/handleOlmRegisterMessage.ts +++ b/server/routers/olm/handleOlmRegisterMessage.ts @@ -1,29 +1,16 @@ -import { - Client, - clientPostureSnapshots, - clientSiteResourcesAssociationsCache, - db, - fingerprints, - orgs, - siteResources -} from "@server/db"; +import { clientPostureSnapshots, db, fingerprints, orgs } from "@server/db"; import { MessageHandler } from "@server/routers/ws"; import { clients, clientSitesAssociationsCache, - exitNodes, Olm, olms, sites } from "@server/db"; -import { and, count, eq, inArray, isNull } from "drizzle-orm"; -import { addPeer, deletePeer } from "../newt/peers"; +import { count, eq } from "drizzle-orm"; import logger from "@server/logger"; -import { generateAliasConfig } from "@server/lib/ip"; -import { generateRemoteSubnets } from "@server/lib/ip"; import { checkOrgAccessPolicy } from "#dynamic/lib/checkOrgAccessPolicy"; import { validateSessionToken } from "@server/auth/sessions/app"; -import config from "@server/lib/config"; import { encodeHexLowerCase } from "@oslojs/encoding"; import { sha256 } from "@oslojs/crypto/sha2"; import { buildSiteConfigurationForOlmClient } from "./buildConfiguration"; @@ -54,10 +41,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { if (!olm.clientId) { logger.warn("Olm client ID not found"); - sendOlmError( - OlmErrorCodes.CLIENT_ID_NOT_FOUND, - olm.olmId - ); + sendOlmError(OlmErrorCodes.CLIENT_ID_NOT_FOUND, olm.olmId); return; } @@ -69,10 +53,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { if (!client) { logger.warn("Client ID not found"); - sendOlmError( - OlmErrorCodes.CLIENT_NOT_FOUND, - olm.olmId - ); + sendOlmError(OlmErrorCodes.CLIENT_NOT_FOUND, olm.olmId); return; } @@ -80,10 +61,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { logger.debug( `Client ${client.clientId} is blocked. Ignoring register.` ); - sendOlmError( - OlmErrorCodes.CLIENT_BLOCKED, - olm.olmId - ); + sendOlmError(OlmErrorCodes.CLIENT_BLOCKED, olm.olmId); return; } @@ -91,10 +69,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { logger.debug( `Client ${client.clientId} approval is pending. Ignoring register.` ); - sendOlmError( - OlmErrorCodes.CLIENT_PENDING, - olm.olmId - ); + sendOlmError(OlmErrorCodes.CLIENT_PENDING, olm.olmId); return; } @@ -106,20 +81,14 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { if (!org) { logger.warn("Org not found"); - sendOlmError( - OlmErrorCodes.ORG_NOT_FOUND, - olm.olmId - ); + sendOlmError(OlmErrorCodes.ORG_NOT_FOUND, olm.olmId); return; } if (orgId) { if (!olm.userId) { logger.warn("Olm has no user ID"); - sendOlmError( - OlmErrorCodes.USER_ID_NOT_FOUND, - olm.olmId - ); + sendOlmError(OlmErrorCodes.USER_ID_NOT_FOUND, olm.olmId); return; } @@ -127,18 +96,12 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { await validateSessionToken(userToken); if (!userSession || !user) { logger.warn("Invalid user session for olm register"); - sendOlmError( - OlmErrorCodes.INVALID_USER_SESSION, - olm.olmId - ); + sendOlmError(OlmErrorCodes.INVALID_USER_SESSION, olm.olmId); return; } if (user.userId !== olm.userId) { logger.warn("User ID mismatch for olm register"); - sendOlmError( - OlmErrorCodes.USER_ID_MISMATCH, - olm.olmId - ); + sendOlmError(OlmErrorCodes.USER_ID_MISMATCH, olm.olmId); return; } @@ -152,14 +115,46 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { sessionId // this is the user token passed in the message }); - if (!policyCheck.allowed) { + if (policyCheck?.error) { + logger.error( + `Error checking access policies for olm user ${olm.userId} in org ${orgId}: ${policyCheck?.error}` + ); + sendOlmError(OlmErrorCodes.ORG_ACCESS_POLICY_DENIED, olm.olmId); + return; + } + + if (policyCheck?.policies?.passwordAge?.compliant) { + logger.warn( + `Olm user ${olm.userId} has non-compliant password age for org ${orgId}` + ); + sendOlmError( + OlmErrorCodes.ORG_ACCESS_POLICY_PASSWORD_EXPIRED, + olm.olmId + ); + return; + } else if (policyCheck?.policies?.maxSessionLength?.compliant) { + logger.warn( + `Olm user ${olm.userId} has non-compliant session length for org ${orgId}` + ); + sendOlmError( + OlmErrorCodes.ORG_ACCESS_POLICY_SESSION_EXPIRED, + olm.olmId + ); + return; + } else if (policyCheck?.policies?.requiredTwoFactor) { + logger.warn( + `Olm user ${olm.userId} does not have 2FA enabled for org ${orgId}` + ); + sendOlmError( + OlmErrorCodes.ORG_ACCESS_POLICY_2FA_REQUIRED, + olm.olmId + ); + return; + } else if (!policyCheck.allowed) { logger.warn( `Olm user ${olm.userId} does not pass access policies for org ${orgId}: ${policyCheck.error}` ); - sendOlmError( - OlmErrorCodes.ACCESS_POLICY_DENIED, - olm.olmId - ); + sendOlmError(OlmErrorCodes.ORG_ACCESS_POLICY_DENIED, olm.olmId); return; } }