add max ttl to renew and login api responses

This commit is contained in:
Maidul Islam
2023-12-12 19:35:45 -05:00
parent f3e8ef1537
commit fbe0cf006f
@@ -3,28 +3,28 @@ import { Types } from "mongoose";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import crypto from "crypto"; import crypto from "crypto";
import bcrypt from "bcrypt"; import bcrypt from "bcrypt";
import { import {
IIdentity, IIdentity,
IIdentityTrustedIp, IIdentityTrustedIp,
IIdentityUniversalAuthClientSecret, IIdentityUniversalAuthClientSecret,
Identity, Identity,
IdentityAccessToken, IdentityAccessToken,
IdentityAuthMethod, IdentityAuthMethod,
IdentityMembershipOrg, IdentityMembershipOrg,
IdentityUniversalAuth, IdentityUniversalAuth,
IdentityUniversalAuthClientSecret, IdentityUniversalAuthClientSecret,
} from "../../models"; } from "../../models";
import { createToken } from "../../helpers/auth"; import { createToken } from "../../helpers/auth";
import { AuthTokenType } from "../../variables"; import { AuthTokenType } from "../../variables";
import { import {
BadRequestError, BadRequestError,
ForbiddenRequestError, ForbiddenRequestError,
ResourceNotFoundError, ResourceNotFoundError,
UnauthorizedRequestError UnauthorizedRequestError
} from "../../utils/errors"; } from "../../utils/errors";
import { import {
getAuthSecret, getAuthSecret,
getSaltRounds getSaltRounds
} from "../../config"; } from "../../config";
import { ActorType, EventType, IRole } from "../../ee/models"; import { ActorType, EventType, IRole } from "../../ee/models";
import { validateRequest } from "../../helpers/validation"; import { validateRequest } from "../../helpers/validation";
@@ -32,12 +32,12 @@ import * as reqValidator from "../../validation/auth";
import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr } from "../../utils/ip"; import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr } from "../../utils/ip";
import { getUserAgentType } from "../../utils/posthog"; import { getUserAgentType } from "../../utils/posthog";
import { EEAuditLogService, EELicenseService } from "../../ee/services"; import { EEAuditLogService, EELicenseService } from "../../ee/services";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getAuthDataOrgPermissions, getAuthDataOrgPermissions,
getOrgRolePermissions, getOrgRolePermissions,
isAtLeastAsPrivilegedOrg isAtLeastAsPrivilegedOrg
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -53,7 +53,7 @@ const packageUniversalAuthClientSecretData = (identityUniversalAuthClientSecret:
createdAt: identityUniversalAuthClientSecret.createdAt, createdAt: identityUniversalAuthClientSecret.createdAt,
updatedAt: identityUniversalAuthClientSecret.updatedAt updatedAt: identityUniversalAuthClientSecret.updatedAt
}); });
/** /**
* Renews an access token by its TTL * Renews an access token by its TTL
* @param req * @param req
@@ -86,9 +86,6 @@ export const renewAccessToken = async (req: Request, res: Response) => {
createdAt: accessTokenCreatedAt createdAt: accessTokenCreatedAt
} = identityAccessToken; } = identityAccessToken;
if (accessTokenTTL === accessTokenMaxTTL) throw UnauthorizedRequestError({
message: "Failed to renew non-renewable access token"
});
// ttl check // ttl check
if (accessTokenTTL > 0) { if (accessTokenTTL > 0) {
@@ -141,6 +138,7 @@ export const renewAccessToken = async (req: Request, res: Response) => {
return res.status(200).send({ return res.status(200).send({
accessToken, accessToken,
expiresIn: identityAccessToken.accessTokenTTL, expiresIn: identityAccessToken.accessTokenTTL,
accessTokenMaxTTL: identityAccessToken.accessTokenMaxTTL,
tokenType: "Bearer" tokenType: "Bearer"
}); });
} }
@@ -162,7 +160,7 @@ export const loginIdentityUniversalAuth = async (req: Request, res: Response) =>
const identityUniversalAuth = await IdentityUniversalAuth.findOne({ const identityUniversalAuth = await IdentityUniversalAuth.findOne({
clientId clientId
}).populate<{ identity: IIdentity }>("identity"); }).populate<{ identity: IIdentity }>("identity");
if (!identityUniversalAuth) throw UnauthorizedRequestError(); if (!identityUniversalAuth) throw UnauthorizedRequestError();
checkIPAgainstBlocklist({ checkIPAgainstBlocklist({
@@ -237,16 +235,16 @@ export const loginIdentityUniversalAuth = async (req: Request, res: Response) =>
// increment usage count by 1 // increment usage count by 1
await IdentityUniversalAuthClientSecret await IdentityUniversalAuthClientSecret
.findByIdAndUpdate( .findByIdAndUpdate(
validatedClientSecretDatum._id, validatedClientSecretDatum._id,
{ {
clientSecretLastUsedAt: new Date(), clientSecretLastUsedAt: new Date(),
$inc: { clientSecretNumUses: 1 } $inc: { clientSecretNumUses: 1 }
}, },
{ {
new: true new: true
} }
); );
const identityAccessToken = await new IdentityAccessToken({ const identityAccessToken = await new IdentityAccessToken({
identity: identityUniversalAuth.identity, identity: identityUniversalAuth.identity,
@@ -300,7 +298,8 @@ export const loginIdentityUniversalAuth = async (req: Request, res: Response) =>
return res.status(200).send({ return res.status(200).send({
accessToken, accessToken,
expiresIn: identityUniversalAuth.accessTokenTTL, expiresIn: identityUniversalAuth.accessTokenTTL,
tokenType: "Bearer" accessTokenMaxTTL: identityUniversalAuth.accessTokenMaxTTL,
tokenType: "Bearer",
}); });
} }
@@ -328,7 +327,7 @@ export const addIdentityUniversalAuth = async (req: Request, res: Response) => {
if (!identityMembershipOrg) throw ResourceNotFoundError({ if (!identityMembershipOrg) throw ResourceNotFoundError({
message: `Failed to find identity with id ${identityId}` message: `Failed to find identity with id ${identityId}`
}); });
if (identityMembershipOrg.identity?.authMethod) throw BadRequestError({ if (identityMembershipOrg.identity?.authMethod) throw BadRequestError({
message: "Failed to add universal auth to already-configured identity" message: "Failed to add universal auth to already-configured identity"
}); });
@@ -377,7 +376,7 @@ export const addIdentityUniversalAuth = async (req: Request, res: Response) => {
return extractIPDetails(accessTokenTrustedIp.ipAddress); return extractIPDetails(accessTokenTrustedIp.ipAddress);
}); });
const identityUniversalAuth = await new IdentityUniversalAuth({ const identityUniversalAuth = await new IdentityUniversalAuth({
identity: identityMembershipOrg.identity._id, identity: identityMembershipOrg.identity._id,
clientId: crypto.randomUUID(), clientId: crypto.randomUUID(),
@@ -387,7 +386,7 @@ export const addIdentityUniversalAuth = async (req: Request, res: Response) => {
accessTokenNumUsesLimit, accessTokenNumUsesLimit,
accessTokenTrustedIps: reformattedAccessTokenTrustedIps, accessTokenTrustedIps: reformattedAccessTokenTrustedIps,
}).save(); }).save();
await Identity.findByIdAndUpdate( await Identity.findByIdAndUpdate(
identityMembershipOrg.identity._id, identityMembershipOrg.identity._id,
{ {
@@ -439,7 +438,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
if (!identityMembershipOrg) throw ResourceNotFoundError({ if (!identityMembershipOrg) throw ResourceNotFoundError({
message: `Failed to find identity with id ${identityId}` message: `Failed to find identity with id ${identityId}`
}); });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.UNIVERSAL_AUTH) throw BadRequestError({ if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.UNIVERSAL_AUTH) throw BadRequestError({
message: "Failed to add universal auth to already-configured identity" message: "Failed to add universal auth to already-configured identity"
}); });
@@ -490,7 +489,7 @@ export const updateIdentityUniversalAuth = async (req: Request, res: Response) =
return extractIPDetails(accessTokenTrustedIp.ipAddress); return extractIPDetails(accessTokenTrustedIp.ipAddress);
}); });
} }
const identityUniversalAuth = await IdentityUniversalAuth.findOneAndUpdate( const identityUniversalAuth = await IdentityUniversalAuth.findOneAndUpdate(
{ {
identity: identityMembershipOrg.identity._id, identity: identityMembershipOrg.identity._id,
@@ -531,7 +530,7 @@ export const getIdentityUniversalAuth = async (req: Request, res: Response) => {
const { const {
params: { identityId } params: { identityId }
} = await validateRequest(reqValidator.GetUniversalAuthForIdentityV1, req); } = await validateRequest(reqValidator.GetUniversalAuthForIdentityV1, req);
const identityMembershipOrg = await IdentityMembershipOrg const identityMembershipOrg = await IdentityMembershipOrg
.findOne({ .findOne({
identity: new Types.ObjectId(identityId) identity: new Types.ObjectId(identityId)
@@ -558,7 +557,7 @@ export const getIdentityUniversalAuth = async (req: Request, res: Response) => {
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.UNIVERSAL_AUTH) throw BadRequestError({ if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.UNIVERSAL_AUTH) throw BadRequestError({
message: "The identity does not have universal auth configured" message: "The identity does not have universal auth configured"
}); });
const identityUniversalAuth = await IdentityUniversalAuth.findOne({ const identityUniversalAuth = await IdentityUniversalAuth.findOne({
identity: identityMembershipOrg.identity._id, identity: identityMembershipOrg.identity._id,
}); });
@@ -625,11 +624,11 @@ export const createUniversalAuthClientSecret = async (req: Request, res: Respons
const clientSecret = crypto.randomBytes(32).toString("hex"); const clientSecret = crypto.randomBytes(32).toString("hex");
const clientSecretHash = await bcrypt.hash(clientSecret, await getSaltRounds()); const clientSecretHash = await bcrypt.hash(clientSecret, await getSaltRounds());
const identityUniversalAuth = await IdentityUniversalAuth.findOne({ const identityUniversalAuth = await IdentityUniversalAuth.findOne({
identity: identityMembershipOrg.identity._id identity: identityMembershipOrg.identity._id
}); });
if (!identityUniversalAuth) throw ResourceNotFoundError(); if (!identityUniversalAuth) throw ResourceNotFoundError();
const identityUniversalAuthClientSecret = await new IdentityUniversalAuthClientSecret({ const identityUniversalAuthClientSecret = await new IdentityUniversalAuthClientSecret({
@@ -665,7 +664,7 @@ export const getUniversalAuthClientSecrets = async (req: Request, res: Response)
const { const {
params: { identityId } params: { identityId }
} = await validateRequest(reqValidator.GetUniversalAuthClientSecretsV1, req); } = await validateRequest(reqValidator.GetUniversalAuthClientSecretsV1, req);
const identityMembershipOrg = await IdentityMembershipOrg.findOne({ const identityMembershipOrg = await IdentityMembershipOrg.findOne({
identity: new Types.ObjectId(identityId) identity: new Types.ObjectId(identityId)
}).populate<{ }).populate<{
@@ -725,7 +724,7 @@ export const revokeUniversalAuthClientSecret = async (req: Request, res: Respons
const { const {
params: { identityId, clientSecretId } params: { identityId, clientSecretId }
} = await validateRequest(reqValidator.RevokeUniversalAuthClientSecretV1, req); } = await validateRequest(reqValidator.RevokeUniversalAuthClientSecretV1, req);
const identityMembershipOrg = await IdentityMembershipOrg const identityMembershipOrg = await IdentityMembershipOrg
.findOne({ .findOne({
identity: new Types.ObjectId(identityId) identity: new Types.ObjectId(identityId)
@@ -773,7 +772,7 @@ export const revokeUniversalAuthClientSecret = async (req: Request, res: Respons
); );
if (!clientSecretData) throw ResourceNotFoundError(); if (!clientSecretData) throw ResourceNotFoundError();
await EEAuditLogService.createAuditLog( await EEAuditLogService.createAuditLog(
req.authData, req.authData,
{ {