Skip to content

Commit

Permalink
feat!: update createNewSession types/code to match new CDI version ch…
Browse files Browse the repository at this point in the history
…ecking the tenantId when creating new sessions
  • Loading branch information
porcellus committed Nov 11, 2024
1 parent 9937dd2 commit a093bc5
Show file tree
Hide file tree
Showing 16 changed files with 287 additions and 100 deletions.
3 changes: 3 additions & 0 deletions lib/build/authUtils.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions lib/build/authUtils.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion lib/build/recipe/emailverification/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class Recipe extends recipeModule_1.default {
input.userContext
);
// create a new session and return that..
return await session_1.default.createNewSession(
const createNewSessionResponse = await session_1.default.createNewSession(
input.req,
input.res,
input.session.getTenantId(),
Expand All @@ -234,6 +234,14 @@ class Recipe extends recipeModule_1.default {
{},
input.userContext
);
if (createNewSessionResponse.status !== "OK") {
// This means that the user was disassociated from the tenant in some kind of race condition (since we checked above)
throw new error_2.default({
type: error_2.default.UNAUTHORISED,
message: createNewSessionResponse.status,
});
}
return createNewSessionResponse.session;
}
} else {
logger_1.logDebugMessage(
Expand Down
20 changes: 18 additions & 2 deletions lib/build/recipe/session/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,31 @@ export default class SessionWrapper {
accessTokenPayload?: any,
sessionDataInDatabase?: any,
userContext?: Record<string, any>
): Promise<SessionContainer>;
): Promise<
| {
status: "OK";
session: SessionContainer;
}
| {
status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR";
}
>;
static createNewSessionWithoutRequestResponse(
tenantId: string,
recipeUserId: RecipeUserId,
accessTokenPayload?: any,
sessionDataInDatabase?: any,
disableAntiCsrf?: boolean,
userContext?: Record<string, any>
): Promise<SessionContainer>;
): Promise<
| {
status: "OK";
session: SessionContainer;
}
| {
status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR";
}
>;
static validateClaimsForSessionHandle(
sessionHandle: string,
overrideGlobalClaimValidators?: (
Expand Down
44 changes: 28 additions & 16 deletions lib/build/recipe/session/recipeImplementation.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,28 @@ function getRecipeInterface(querier, config, appInfo, getRecipeImplAfterOverride
sessionDataInDatabase,
userContext
);
logger_1.logDebugMessage("createNewSession: Finished");
logger_1.logDebugMessage("createNewSession: Finished with status " + response.status);
if (response.status !== "OK") {
return response;
}
const payload = jwt_1.parseJWTWithoutSignatureVerification(response.accessToken.token).payload;
return new sessionClass_1.default(
helpers,
response.accessToken.token,
cookieAndHeaders_1.buildFrontToken(response.session.userId, response.accessToken.expiry, payload),
response.refreshToken,
response.antiCsrfToken,
response.session.handle,
response.session.userId,
response.session.recipeUserId,
payload,
undefined,
true,
tenantId
);
return {
status: "OK",
session: new sessionClass_1.default(
helpers,
response.accessToken.token,
cookieAndHeaders_1.buildFrontToken(response.session.userId, response.accessToken.expiry, payload),
response.refreshToken,
response.antiCsrfToken,
response.session.handle,
response.session.userId,
response.session.recipeUserId,
payload,
undefined,
true,
tenantId
),
};
},
getGlobalClaimValidators: async function (input) {
return input.claimValidatorsAddedByOtherRecipes;
Expand Down Expand Up @@ -244,7 +250,13 @@ function getRecipeInterface(querier, config, appInfo, getRecipeImplAfterOverride
config.useDynamicAccessTokenSigningKey,
userContext
);
logger_1.logDebugMessage("refreshSession: Success!");
logger_1.logDebugMessage("refreshSession: Finished with status " + response.status);
if (response.status !== "OK") {
throw new error_1.default({
type: "UNAUTHORISED",
message: response.message,
});
}
const payload = jwt_1.parseJWTWithoutSignatureVerification(response.accessToken.token).payload;
return new sessionClass_1.default(
helpers,
Expand Down
10 changes: 9 additions & 1 deletion lib/build/recipe/session/sessionFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ async function createNewSession(
requestBody,
userContext
);
if (response.status !== "OK") {
return {
status: response.status,
message: response.message,
};
}
return {
status: response.status,
session: {
handle: response.session.handle,
userId: response.session.userId,
Expand Down Expand Up @@ -324,6 +331,7 @@ async function refreshSession(
);
if (response.status === "OK") {
return {
status: "OK",
session: {
handle: response.session.handle,
userId: response.session.userId,
Expand All @@ -343,7 +351,7 @@ async function refreshSession(
},
antiCsrfToken: response.antiCsrfToken,
};
} else if (response.status === "UNAUTHORISED") {
} else if (response.status === "UNAUTHORISED" || response.status === "USER_DOES_NOT_BELONG_TO_TENANT_ERROR") {
logger_1.logDebugMessage("refreshSession: Returning UNAUTHORISED because of core response");
throw new error_1.default({
message: response.message,
Expand Down
10 changes: 9 additions & 1 deletion lib/build/recipe/session/sessionRequestFunctions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,12 @@ export declare function createNewSessionInRequest({
appInfo: NormalisedAppinfo;
sessionDataInDatabase: any;
tenantId: string;
}): Promise<SessionContainerInterface>;
}): Promise<
| {
status: "OK";
session: SessionContainerInterface;
}
| {
status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR";
}
>;
8 changes: 6 additions & 2 deletions lib/build/recipe/session/sessionRequestFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ async function createNewSessionInRequest({
);
}
const disableAntiCsrf = outputTransferMethod === "header";
const session = await recipeInstance.recipeInterfaceImpl.createNewSession({
const createNewSessionResponse = await recipeInstance.recipeInterfaceImpl.createNewSession({
userId,
recipeUserId,
accessTokenPayload: finalAccessTokenPayload,
Expand All @@ -442,6 +442,10 @@ async function createNewSessionInRequest({
tenantId,
userContext,
});
if (createNewSessionResponse.status !== "OK") {
return createNewSessionResponse;
}
const session = createNewSessionResponse.session;
logger_1.logDebugMessage("createNewSession: Session created in core built");
for (const transferMethod of constants_1.availableTokenTransferMethods) {
if (
Expand All @@ -461,6 +465,6 @@ async function createNewSessionInRequest({
userContext
);
logger_1.logDebugMessage("createNewSession: Attached new tokens to res");
return session;
return createNewSessionResponse;
}
exports.createNewSessionInRequest = createNewSessionInRequest;
40 changes: 27 additions & 13 deletions lib/build/recipe/session/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,24 @@ export declare type TokenInfo = {
expiry: number;
createdTime: number;
};
export declare type CreateOrRefreshAPIResponse = {
session: {
handle: string;
userId: string;
recipeUserId: RecipeUserId;
userDataInJWT: any;
tenantId: string;
};
accessToken: TokenInfo;
refreshToken: TokenInfo;
antiCsrfToken: string | undefined;
};
export declare type CreateOrRefreshAPIResponse =
| {
status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR";
message: string;
}
| {
status: "OK";
session: {
handle: string;
userId: string;
recipeUserId: RecipeUserId;
userDataInJWT: any;
tenantId: string;
};
accessToken: TokenInfo;
refreshToken: TokenInfo;
antiCsrfToken: string | undefined;
};
export interface ErrorHandlers {
onUnauthorised?: ErrorHandlerMiddleware;
onTryRefreshToken?: ErrorHandlerMiddleware;
Expand Down Expand Up @@ -147,7 +153,15 @@ export declare type RecipeInterface = {
disableAntiCsrf?: boolean;
tenantId: string;
userContext: UserContext;
}): Promise<SessionContainerInterface>;
}): Promise<
| {
status: "OK";
session: SessionContainerInterface;
}
| {
status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR";
}
>;
getGlobalClaimValidators(input: {
tenantId: string;
userId: string;
Expand Down
34 changes: 31 additions & 3 deletions lib/ts/authUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,11 @@ export const AuthUtils = {
userContext: UserContext;
req: BaseRequest;
res: BaseResponse;
}): Promise<{ status: "OK"; session: SessionContainerInterface; user: User } | { status: "SIGN_IN_NOT_ALLOWED" }> {
}): Promise<
| { status: "OK"; session: SessionContainerInterface; user: User }
| { status: "SIGN_IN_NOT_ALLOWED" }
| { status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR" }
> {
logDebugMessage(
`postAuthChecks called ${session !== undefined ? "with" : "without"} a session to ${
isSignUp ? "sign in" : "sign up"
Expand All @@ -277,15 +281,39 @@ export const AuthUtils = {
} else {
// If the new user wasn't linked to the current one, we overwrite the session
// Note: we could also get here if MFA is enabled, but the app didn't want to link the user to the session user.
respSession = await Session.createNewSession(req, res, tenantId, recipeUserId, {}, {}, userContext);
const createNewSessionResponse = await Session.createNewSession(
req,
res,
tenantId,
recipeUserId,
{},
{},
userContext
);
if (createNewSessionResponse.status !== "OK") {
return { status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR" };
}
respSession = createNewSessionResponse.session;
if (mfaInstance !== undefined) {
await MultiFactorAuth.markFactorAsCompleteInSession(respSession!, factorId, userContext);
}
}
} else {
logDebugMessage(`postAuthChecks creating session for first factor sign in/up`);
// If there is no input session, we do not need to do anything other checks and create a new session
respSession = await Session.createNewSession(req, res, tenantId, recipeUserId, {}, {}, userContext);
const createNewSessionResponse = await Session.createNewSession(
req,
res,
tenantId,
recipeUserId,
{},
{},
userContext
);
if (createNewSessionResponse.status !== "OK") {
return { status: "USER_DOES_NOT_BELONG_TO_TENANT_ERROR" };
}
respSession = createNewSessionResponse.session;

// Here we can always mark the factor as completed, since we just created the session
if (mfaInstance !== undefined) {
Expand Down
12 changes: 11 additions & 1 deletion lib/ts/recipe/emailverification/recipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ export default class Recipe extends RecipeModule {
);

// create a new session and return that..
return await Session.createNewSession(
const createNewSessionResponse = await Session.createNewSession(
input.req,
input.res,
input.session.getTenantId(),
Expand All @@ -353,6 +353,16 @@ export default class Recipe extends RecipeModule {
{},
input.userContext
);

if (createNewSessionResponse.status !== "OK") {
// This means that the user was disassociated from the tenant in some kind of race condition (since we checked above)
throw new SessionError({
type: SessionError.UNAUTHORISED,
message: createNewSessionResponse.status,
});
}

return createNewSessionResponse.session;
}
} else {
logDebugMessage(
Expand Down
Loading

0 comments on commit a093bc5

Please sign in to comment.