Merge pull request #28967 from JessicaJHee/dangerouslyAllowSignInWithoutUserInCatalog-config

introduce dangerouslyAllowSignInWithoutUserInCatalog auth resolver config
This commit is contained in:
Patrik Oldsberg
2025-05-13 12:18:55 +02:00
committed by GitHub
75 changed files with 840 additions and 166 deletions
+17 -1
View File
@@ -110,6 +110,17 @@ export type AuthResolverContext = {
}>;
signInWithCatalogUser(
query: AuthResolverCatalogUserQuery,
options?: {
dangerousEntityRefFallback?: {
entityRef:
| string
| {
kind?: string;
namespace?: string;
name: string;
};
};
},
): Promise<BackstageSignInResult>;
resolveOwnershipEntityRefs(entity: Entity): Promise<{
ownershipEntityRefs: string[];
@@ -146,12 +157,17 @@ export type ClientAuthResponse<TProviderInfo> = {
export namespace commonSignInResolvers {
const emailMatchingUserEntityProfileEmail: SignInResolverFactory<
unknown,
unknown
| {
allowedDomains?: string[] | undefined;
dangerouslyAllowSignInWithoutUserInCatalog?: boolean | undefined;
}
| undefined
>;
const emailLocalPartMatchingUserEntityName: SignInResolverFactory<
unknown,
| {
allowedDomains?: string[] | undefined;
dangerouslyAllowSignInWithoutUserInCatalog?: boolean | undefined;
}
| undefined
>;
@@ -35,7 +35,13 @@ export namespace commonSignInResolvers {
*/
export const emailMatchingUserEntityProfileEmail =
createSignInResolverFactory({
create() {
optionsSchema: z
.object({
allowedDomains: z.array(z.string()).optional(),
dangerouslyAllowSignInWithoutUserInCatalog: z.boolean().optional(),
})
.optional(),
create(options = {}) {
return async (info, ctx) => {
const { profile } = info;
@@ -59,11 +65,19 @@ export namespace commonSignInResolvers {
const [_, name, _plus, domain] = m;
const noPlusEmail = `${name}${domain}`;
return ctx.signInWithCatalogUser({
filter: {
'spec.profile.email': noPlusEmail,
return ctx.signInWithCatalogUser(
{
filter: {
'spec.profile.email': noPlusEmail,
},
},
});
{
dangerousEntityRefFallback:
options?.dangerouslyAllowSignInWithoutUserInCatalog
? { entityRef: { name: noPlusEmail } }
: undefined,
},
);
}
}
// Email had no plus addressing or is missing in the catalog, forward failure
@@ -82,6 +96,7 @@ export namespace commonSignInResolvers {
optionsSchema: z
.object({
allowedDomains: z.array(z.string()).optional(),
dangerouslyAllowSignInWithoutUserInCatalog: z.boolean().optional(),
})
.optional(),
create(options = {}) {
@@ -102,10 +117,15 @@ export namespace commonSignInResolvers {
'Sign-in user email is not from an allowed domain',
);
}
return ctx.signInWithCatalogUser({
entityRef: { name: localPart },
});
return ctx.signInWithCatalogUser(
{ entityRef: { name: localPart } },
{
dangerousEntityRefFallback:
options?.dangerouslyAllowSignInWithoutUserInCatalog
? { entityRef: { name: localPart } }
: undefined,
},
);
};
},
});
+16
View File
@@ -162,10 +162,26 @@ export type AuthResolverContext = {
* Finds a single user in the catalog using the provided query, and then
* issues an identity for that user using default ownership resolution.
*
* If the user is not found, an optional `dangerousEntityRefFallback`
* entity ref can be provided to allow sign-in to proceed by issuing an
* identity based on the given ref. This bypasses the requirement for the
* user to exist in the catalog and should be used with caution.
*
* See {@link AuthResolverCatalogUserQuery} for details.
*/
signInWithCatalogUser(
query: AuthResolverCatalogUserQuery,
options?: {
dangerousEntityRefFallback?: {
entityRef:
| string
| {
kind?: string;
namespace?: string;
name: string;
};
};
},
): Promise<BackstageSignInResult>;
/**