auth-node: add readDeclarativeSignInResolver

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-08-07 10:34:08 +02:00
parent bbeb816313
commit d30b4e387a
3 changed files with 88 additions and 1 deletions
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { readDeclarativeSignInResolver } from '../sign-in';
import { AuthProviderFactory, SignInResolver } from '../types';
import { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler';
import { createOAuthRouteHandlers } from './createOAuthRouteHandlers';
@@ -23,6 +24,7 @@ import {
OAuthAuthenticatorResult,
OAuthProfileTransform,
} from './types';
import { SignInResolverFactory } from '../sign-in/createSignInResolverFactory';
/** @public */
export function createOAuthProviderFactory<TProfile>(options: {
@@ -30,9 +32,21 @@ export function createOAuthProviderFactory<TProfile>(options: {
stateTransform?: OAuthStateTransform;
profileTransform?: OAuthProfileTransform<TProfile>;
signInResolver?: SignInResolver<OAuthAuthenticatorResult<TProfile>>;
signInResolverFactories?: {
[name in string]: SignInResolverFactory<
OAuthAuthenticatorResult<TProfile>,
unknown
>;
};
}): AuthProviderFactory {
return ctx => {
return OAuthEnvironmentHandler.mapConfig(ctx.config, envConfig => {
const signInResolver =
options.signInResolver ??
readDeclarativeSignInResolver(envConfig, {
signInResolverFactories: options.signInResolverFactories,
});
return createOAuthRouteHandlers<TProfile>({
authenticator: options.authenticator,
appUrl: ctx.appUrl,
@@ -44,7 +58,7 @@ export function createOAuthProviderFactory<TProfile>(options: {
resolverContext: ctx.resolverContext,
stateTransform: options.stateTransform,
profileTransform: options.profileTransform,
signInResolver: options.signInResolver,
signInResolver,
});
});
};
+4
View File
@@ -15,3 +15,7 @@
*/
export { createSignInResolverFactory } from './createSignInResolverFactory';
export {
readDeclarativeSignInResolver,
type ReadDeclarativeSignInResolverOptions,
} from './readDeclarativeSignInResolver';
@@ -0,0 +1,69 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { SignInResolver } from '../types';
import { SignInResolverFactory } from './createSignInResolverFactory';
/** @public */
export interface ReadDeclarativeSignInResolverOptions<TAuthResult> {
config: Config;
signInResolverFactories: {
[name in string]: SignInResolverFactory<TAuthResult, unknown>;
};
}
/** @public */
export function readDeclarativeSignInResolver<TAuthResult>(
options: ReadDeclarativeSignInResolverOptions<TAuthResult>,
): SignInResolver<TAuthResult> | undefined {
const resolvers =
options.config
.getOptionalConfigArray('signIn.resolvers')
?.map(resolverConfig => {
const resolverName = resolverConfig.getString('resolver');
if (!Object.hasOwn(options.signInResolverFactories, resolverName)) {
throw new Error(
`Sign-in resolver '${resolverName}' is not available`,
);
}
const resolver = options.signInResolverFactories[resolverName];
const { resolver: _ignored, ...resolverOptions } =
resolverConfig.get<JsonObject>();
return resolver(resolverOptions);
}) ?? [];
if (resolvers.length === 0) {
return undefined;
}
return async (profile, context) => {
for (const resolver of resolvers ?? []) {
try {
return await resolver(profile, context);
} catch (error) {
if (error?.name === 'NotFoundError') {
continue;
}
throw error;
}
}
throw new Error('Failed to sign-in, unable to resolve user identity');
};
}