mirror of
https://github.com/wassname/talk.git
synced 2026-08-08 11:28:12 +08:00
feat: added initial server sso key rotation semantics (#2696)
This commit is contained in:
committed by
Kim Gardner
parent
59b8dfccda
commit
2dbba52fbd
@@ -7,6 +7,8 @@ import {
|
||||
} from "coral-server/graph/tenant/schema/__generated__/types";
|
||||
import { translate } from "coral-server/services/i18n";
|
||||
|
||||
import { SSOKey } from "../settings";
|
||||
|
||||
export const getDefaultReactionConfiguration = (
|
||||
bundle: FluentBundle
|
||||
): GQLReactionConfiguration => ({
|
||||
@@ -28,10 +30,19 @@ export const getDefaultStaffConfiguration = (
|
||||
label: translate(bundle, "Staff", "staff-label"),
|
||||
});
|
||||
|
||||
export function generateSSOKey() {
|
||||
export function generateRandomString(size: number, drift = 5) {
|
||||
return crypto
|
||||
.randomBytes(size + Math.floor(Math.random() * drift))
|
||||
.toString("hex");
|
||||
}
|
||||
|
||||
export function generateSSOKey(createdAt: Date): SSOKey {
|
||||
// Generate a new key. We generate a key of minimum length 32 up to 37 bytes,
|
||||
// as 16 was the minimum length recommended.
|
||||
//
|
||||
// Reference: https://security.stackexchange.com/a/96176
|
||||
return crypto.randomBytes(32 + Math.floor(Math.random() * 5)).toString("hex");
|
||||
const secret = generateRandomString(32, 5);
|
||||
const kid = generateRandomString(8, 3);
|
||||
|
||||
return { kid, secret, createdAt };
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ export async function createTenant(
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
key: generateSSOKey(),
|
||||
keyGeneratedAt: now,
|
||||
// TODO: [CORL-754] (wyattjoh) remove this in favor of generating this when needed
|
||||
keys: [generateSSOKey(now)],
|
||||
},
|
||||
oidc: {
|
||||
enabled: false,
|
||||
@@ -277,25 +277,17 @@ export async function updateTenant(
|
||||
* for the specified Tenant. All existing user sessions signed with the old
|
||||
* secret will be invalidated.
|
||||
*/
|
||||
export async function regenerateTenantSSOKey(mongo: Db, id: string) {
|
||||
// Construct the update.
|
||||
const update: DeepPartial<Tenant> = {
|
||||
auth: {
|
||||
integrations: {
|
||||
sso: {
|
||||
key: generateSSOKey(),
|
||||
keyGeneratedAt: new Date(),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export async function createTenantSSOKey(mongo: Db, id: string, now: Date) {
|
||||
// Construct the new key.
|
||||
const key = generateSSOKey(now);
|
||||
|
||||
// Update the Tenant with this new key.
|
||||
const result = await collection(mongo).findOneAndUpdate(
|
||||
{ id },
|
||||
// Serialize the deep update into the Tenant.
|
||||
{
|
||||
$set: dotize(update),
|
||||
$push: {
|
||||
"auth.integrations.sso.keys": key,
|
||||
},
|
||||
},
|
||||
// False to return the updated document instead of the original
|
||||
// document.
|
||||
@@ -304,3 +296,29 @@ export async function regenerateTenantSSOKey(mongo: Db, id: string) {
|
||||
|
||||
return result.value || null;
|
||||
}
|
||||
|
||||
export async function deprecateTenantSSOKey(
|
||||
mongo: Db,
|
||||
id: string,
|
||||
kid: string,
|
||||
deprecateAt: Date
|
||||
) {
|
||||
// Update the tenant.
|
||||
const result = await collection(mongo).findOneAndUpdate(
|
||||
{ id },
|
||||
{
|
||||
$set: {
|
||||
"auth.integrations.sso.keys.$[keys].deprecateAt": deprecateAt,
|
||||
},
|
||||
},
|
||||
{
|
||||
// False to return the updated document instead of the original
|
||||
// document.
|
||||
returnOriginal: false,
|
||||
// Add an ArrayFilter to only update one of the keys.
|
||||
arrayFilters: [{ "keys.kid": kid }],
|
||||
}
|
||||
);
|
||||
|
||||
return result.value || null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user