mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 06:28:50 +00:00
feat: added dal to remove expired token for queue and fixed token validation check missing num uses increment and maxTTL failed check
This commit is contained in:
@@ -37,5 +37,48 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...identityAccessTokenOrm, findOne };
|
const removeExpiredTokens = async (tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const docs = (tx || db)(TableName.IdentityAccessToken)
|
||||||
|
.where({
|
||||||
|
isAccessTokenRevoked: true
|
||||||
|
})
|
||||||
|
.orWhere((qb) => {
|
||||||
|
void qb
|
||||||
|
.where("accessTokenNumUsesLimit", ">", 0)
|
||||||
|
.andWhere(
|
||||||
|
"accessTokenNumUses",
|
||||||
|
">",
|
||||||
|
db.ref("accessTokenNumUsesLimit").withSchema(TableName.IdentityAccessToken)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.orWhere((qb) => {
|
||||||
|
void qb.where("accessTokenTTL", ">", 0).andWhere((qb2) => {
|
||||||
|
void qb2
|
||||||
|
.where((qb3) => {
|
||||||
|
void qb3
|
||||||
|
.whereNotNull("accessTokenLastRenewedAt")
|
||||||
|
// accessTokenLastRenewedAt + convert_integer_to_seconds(accessTokenTTL) < present_date
|
||||||
|
.andWhereRaw(
|
||||||
|
`"${TableName.IdentityAccessToken}"."accessTokenLastRenewedAt" + make_interval(secs => "${TableName.IdentityAccessToken}"."accessTokenTTL") < NOW()`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.orWhere((qb3) => {
|
||||||
|
void qb3
|
||||||
|
.whereNull("accessTokenLastRenewedAt")
|
||||||
|
// created + convert_integer_to_seconds(accessTokenTTL) < present_date
|
||||||
|
.andWhereRaw(
|
||||||
|
`"${TableName.IdentityAccessToken}"."createdAt" + make_interval(secs => "${TableName.IdentityAccessToken}"."accessTokenTTL") < NOW()`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.delete();
|
||||||
|
return await docs;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "IdentityAccesTokenPrune" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...identityAccessTokenOrm, findOne, removeExpiredTokens };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,17 +21,18 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityOrgMembershipDAL
|
identityOrgMembershipDAL
|
||||||
}: TIdentityAccessTokenServiceFactoryDep) => {
|
}: TIdentityAccessTokenServiceFactoryDep) => {
|
||||||
const validateAccessTokenExp = (identityAccessToken: TIdentityAccessTokens) => {
|
const validateAccessTokenExp = async (identityAccessToken: TIdentityAccessTokens) => {
|
||||||
const {
|
const {
|
||||||
|
id: tokenId,
|
||||||
accessTokenTTL,
|
accessTokenTTL,
|
||||||
accessTokenNumUses,
|
accessTokenNumUses,
|
||||||
accessTokenNumUsesLimit,
|
accessTokenNumUsesLimit,
|
||||||
accessTokenLastRenewedAt,
|
accessTokenLastRenewedAt,
|
||||||
accessTokenMaxTTL,
|
|
||||||
createdAt: accessTokenCreatedAt
|
createdAt: accessTokenCreatedAt
|
||||||
} = identityAccessToken;
|
} = identityAccessToken;
|
||||||
|
|
||||||
if (accessTokenNumUsesLimit > 0 && accessTokenNumUses > 0 && accessTokenNumUses >= accessTokenNumUsesLimit) {
|
if (accessTokenNumUsesLimit > 0 && accessTokenNumUses > 0 && accessTokenNumUses >= accessTokenNumUsesLimit) {
|
||||||
|
await identityAccessTokenDAL.deleteById(tokenId);
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Unable to renew because access token number of uses limit reached"
|
message: "Unable to renew because access token number of uses limit reached"
|
||||||
});
|
});
|
||||||
@@ -46,41 +47,26 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
||||||
const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds);
|
const expirationDate = new Date(accessTokenRenewed.getTime() + ttlInMilliseconds);
|
||||||
|
|
||||||
if (currentDate > expirationDate)
|
if (currentDate > expirationDate) {
|
||||||
|
await identityAccessTokenDAL.deleteById(tokenId);
|
||||||
throw new UnauthorizedError({
|
throw new UnauthorizedError({
|
||||||
message: "Failed to renew MI access token due to TTL expiration"
|
message: "Failed to renew MI access token due to TTL expiration"
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// access token has never been renewed
|
// access token has never been renewed
|
||||||
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
||||||
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
const ttlInMilliseconds = Number(accessTokenTTL) * 1000;
|
||||||
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
||||||
|
|
||||||
if (currentDate > expirationDate)
|
if (currentDate > expirationDate) {
|
||||||
|
await identityAccessTokenDAL.deleteById(tokenId);
|
||||||
throw new UnauthorizedError({
|
throw new UnauthorizedError({
|
||||||
message: "Failed to renew MI access token due to TTL expiration"
|
message: "Failed to renew MI access token due to TTL expiration"
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// max ttl checks
|
|
||||||
if (Number(accessTokenMaxTTL) > 0) {
|
|
||||||
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
|
||||||
const ttlInMilliseconds = Number(accessTokenMaxTTL) * 1000;
|
|
||||||
const currentDate = new Date();
|
|
||||||
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
|
||||||
|
|
||||||
if (currentDate > expirationDate)
|
|
||||||
throw new UnauthorizedError({
|
|
||||||
message: "Failed to renew MI access token due to Max TTL expiration"
|
|
||||||
});
|
|
||||||
|
|
||||||
const extendToDate = new Date(currentDate.getTime() + Number(accessTokenTTL));
|
|
||||||
if (extendToDate > expirationDate)
|
|
||||||
throw new UnauthorizedError({
|
|
||||||
message: "Failed to renew MI access token past its Max TTL expiration"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
|
const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => {
|
||||||
@@ -97,7 +83,32 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!identityAccessToken) throw new UnauthorizedError();
|
if (!identityAccessToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
validateAccessTokenExp(identityAccessToken);
|
await validateAccessTokenExp(identityAccessToken);
|
||||||
|
|
||||||
|
const { accessTokenMaxTTL, createdAt: accessTokenCreatedAt, accessTokenTTL } = identityAccessToken;
|
||||||
|
|
||||||
|
// max ttl checks - will it go above max ttl
|
||||||
|
if (Number(accessTokenMaxTTL) > 0) {
|
||||||
|
const accessTokenCreated = new Date(accessTokenCreatedAt);
|
||||||
|
const ttlInMilliseconds = Number(accessTokenMaxTTL) * 1000;
|
||||||
|
const currentDate = new Date();
|
||||||
|
const expirationDate = new Date(accessTokenCreated.getTime() + ttlInMilliseconds);
|
||||||
|
|
||||||
|
if (currentDate > expirationDate) {
|
||||||
|
await identityAccessTokenDAL.deleteById(identityAccessToken.id);
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Failed to renew MI access token due to Max TTL expiration"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const extendToDate = new Date(currentDate.getTime() + Number(accessTokenTTL * 1000));
|
||||||
|
if (extendToDate > expirationDate) {
|
||||||
|
await identityAccessTokenDAL.deleteById(identityAccessToken.id);
|
||||||
|
throw new UnauthorizedError({
|
||||||
|
message: "Failed to renew MI access token past its Max TTL expiration"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById(identityAccessToken.id, {
|
const updatedIdentityAccessToken = await identityAccessTokenDAL.updateById(identityAccessToken.id, {
|
||||||
accessTokenLastRenewedAt: new Date()
|
accessTokenLastRenewedAt: new Date()
|
||||||
@@ -113,7 +124,7 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!identityAccessToken) throw new UnauthorizedError();
|
if (!identityAccessToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
if (ipAddress) {
|
if (ipAddress && identityAccessToken) {
|
||||||
checkIPAgainstBlocklist({
|
checkIPAgainstBlocklist({
|
||||||
ipAddress,
|
ipAddress,
|
||||||
trustedIps: identityAccessToken?.accessTokenTrustedIps as TIp[]
|
trustedIps: identityAccessToken?.accessTokenTrustedIps as TIp[]
|
||||||
@@ -128,7 +139,14 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
throw new UnauthorizedError({ message: "Identity does not belong to any organization" });
|
throw new UnauthorizedError({ message: "Identity does not belong to any organization" });
|
||||||
}
|
}
|
||||||
|
|
||||||
validateAccessTokenExp(identityAccessToken);
|
await validateAccessTokenExp(identityAccessToken);
|
||||||
|
|
||||||
|
await identityAccessTokenDAL.updateById(identityAccessToken.id, {
|
||||||
|
accessTokenLastUsedAt: new Date(),
|
||||||
|
$incr: {
|
||||||
|
accessTokenNumUses: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
return { ...identityAccessToken, orgId: identityOrgMembership.orgId };
|
return { ...identityAccessToken, orgId: identityOrgMembership.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user