Make more progress on service token v3

This commit is contained in:
Tuan Dang
2023-09-22 11:19:14 +01:00
parent 84d094b4d8
commit 53856ff868
6 changed files with 74 additions and 5 deletions
+56 -1
View File
@@ -7,6 +7,7 @@ import {
ITokenVersion, ITokenVersion,
IUser, IUser,
ServiceTokenData, ServiceTokenData,
ServiceTokenDataV3,
TokenVersion, TokenVersion,
User, User,
} from "../models"; } from "../models";
@@ -29,6 +30,7 @@ import {
} from "../variables"; } from "../variables";
import { import {
ServiceTokenAuthData, ServiceTokenAuthData,
ServiceTokenV3AuthData,
UserAuthData UserAuthData
} from "../interfaces/middleware"; } from "../interfaces/middleware";
@@ -47,6 +49,9 @@ export const validateAuthMode = ({
headers: { [key: string]: string | string[] | undefined }, headers: { [key: string]: string | string[] | undefined },
acceptedAuthModes: AuthMode[] acceptedAuthModes: AuthMode[]
}) => { }) => {
// TODO: update this to accept service token v3
const apiKey = headers["x-api-key"]; const apiKey = headers["x-api-key"];
const authHeader = headers["authorization"]; const authHeader = headers["authorization"];
@@ -76,6 +81,9 @@ export const validateAuthMode = ({
case "st": case "st":
authMode = AuthMode.SERVICE_TOKEN; authMode = AuthMode.SERVICE_TOKEN;
break; break;
case "proj_token":
authMode = AuthMode.SERVICE_TOKEN_V3;
break;
default: default:
authMode = AuthMode.JWT; authMode = AuthMode.JWT;
} }
@@ -211,8 +219,55 @@ export const getAuthSTDPayload = async ({
userAgent: req.headers["user-agent"] ?? "", userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"]) userAgentType: getUserAgentType(req.headers["user-agent"])
} }
}
// return serviceTokenDataToReturn; /**
* Return service token data V3 payload corresponding to service token [authTokenValue]
* @param {Object} obj
* @param {String} obj.authTokenValue - service token value
* @returns {ServiceTokenData} serviceTokenData - service token data
*/
export const getAuthSTDV3Payload = async ({
req,
authTokenValue,
}: {
req: Request,
authTokenValue: string;
}): Promise<ServiceTokenV3AuthData> => {
const decodedToken = <jwt.UserIDJwtPayload>(
jwt.verify(authTokenValue, "hello") // TODO: change this
);
// perhaps turn this one into a find one and update call?
const serviceTokenData = await ServiceTokenDataV3.findOne({
_id: new Types.ObjectId(decodedToken.serviceTokenDataId),
});
if (!serviceTokenData) {
throw UnauthorizedRequestError({
message: "Failed to authenticate" // standardize auth error messages
});
} else if (serviceTokenData?.expiresAt && new Date(serviceTokenData.expiresAt) < new Date()) {
// case: service token expired
await ServiceTokenDataV3.findByIdAndDelete(serviceTokenData._id);
throw UnauthorizedRequestError({
message: "Failed to authenticate",
});
}
return {
actor: {
type: ActorType.SERVICE, // should this be servicev3 bc the shape of it is different?
metadata: {
serviceId: serviceTokenData._id.toString(),
name: serviceTokenData.name
}
},
authPayload: serviceTokenData,
ipAddress: req.realIP,
userAgent: req.headers["user-agent"] ?? "",
userAgentType: getUserAgentType(req.headers["user-agent"])
}
} }
/** /**
@@ -1,6 +1,7 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { import {
IServiceTokenData, IServiceTokenData,
IServiceTokenDataV3,
IUser, IUser,
} from "../../models"; } from "../../models";
import { import {
@@ -21,6 +22,11 @@ export interface UserAuthData extends BaseAuthData {
authPayload: IUser; authPayload: IUser;
} }
export interface ServiceTokenV3AuthData extends BaseAuthData {
actor: ServiceActor;
authPayload: IServiceTokenDataV3;
}
export interface ServiceTokenAuthData extends BaseAuthData { export interface ServiceTokenAuthData extends BaseAuthData {
actor: ServiceActor; actor: ServiceActor;
authPayload: IServiceTokenData; authPayload: IServiceTokenData;
@@ -28,4 +34,5 @@ export interface ServiceTokenAuthData extends BaseAuthData {
export type AuthData = export type AuthData =
| UserAuthData | UserAuthData
| ServiceTokenV3AuthData
| ServiceTokenAuthData; | ServiceTokenAuthData;
+7 -2
View File
@@ -3,6 +3,7 @@ import { NextFunction, Request, Response } from "express";
import { import {
getAuthAPIKeyPayload, getAuthAPIKeyPayload,
getAuthSTDPayload, getAuthSTDPayload,
getAuthSTDV3Payload,
getAuthUserPayload, getAuthUserPayload,
validateAuthMode, validateAuthMode,
} from "../helpers/auth"; } from "../helpers/auth";
@@ -49,6 +50,12 @@ const requireAuth = ({
}); });
req.serviceTokenData = authData.authPayload; req.serviceTokenData = authData.authPayload;
break; break;
case AuthMode.SERVICE_TOKEN_V3:
authData = await getAuthSTDV3Payload({
req,
authTokenValue
});
break;
case AuthMode.API_KEY: case AuthMode.API_KEY:
authData = await getAuthAPIKeyPayload({ authData = await getAuthAPIKeyPayload({
req, req,
@@ -61,9 +68,7 @@ const requireAuth = ({
req, req,
authTokenValue authTokenValue
}); });
// authPayload = authUserPayload.user;
req.user = authData.authPayload; req.user = authData.authPayload;
// req.tokenVersionId = authUserPayload.tokenVersionId; // TODO
break; break;
} }
+2 -1
View File
@@ -17,7 +17,8 @@ export interface IServiceTokenDataV3 extends Document {
workspace: Types.ObjectId; workspace: Types.ObjectId;
publicKey: string; publicKey: string;
isActive: boolean; isActive: boolean;
lastUsed: Date; lastUsed?: Date;
expiresAt?: Date;
scopes: Array<Scope>; scopes: Array<Scope>;
} }
+1 -1
View File
@@ -154,7 +154,7 @@ export const DeleteIntegrationAuthV1 = z.object({
export const GetIntegrationAuthTeamCityBuildConfigsV1 = z.object({ export const GetIntegrationAuthTeamCityBuildConfigsV1 = z.object({
params:z.object({ params:z.object({
appId:z.string().trim(), appId:z.string().trim().optional(),
integrationAuthId:z.string().trim() integrationAuthId:z.string().trim()
}) })
}) })
+1
View File
@@ -1,6 +1,7 @@
export enum AuthMode { export enum AuthMode {
JWT = "jwt", JWT = "jwt",
SERVICE_TOKEN = "serviceToken", SERVICE_TOKEN = "serviceToken",
SERVICE_TOKEN_V3 = "serviceTokenV3",
API_KEY = "apiKey" API_KEY = "apiKey"
} }