auth-node: add proxy provider APIs

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-08-07 17:44:37 +02:00
parent d3265deba8
commit c3aa1b91e1
5 changed files with 196 additions and 0 deletions
+1
View File
@@ -25,6 +25,7 @@ export * from './flow';
export * from './identity';
export * from './oauth';
export * from './passport';
export * from './proxy';
export * from './sign-in';
export type {
AuthProviderConfig,
@@ -0,0 +1,60 @@
/*
* 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 {
readDeclarativeSignInResolver,
SignInResolverFactory,
} from '../sign-in';
import {
AuthProviderFactory,
ProfileTransform,
SignInResolver,
} from '../types';
import { createProxyAuthRouteHandlers } from './createProxyRouteHandlers';
import { ProxyAuthenticator } from './types';
export function createProxyAuthProviderFactory<TResult>(options: {
authenticator: ProxyAuthenticator<unknown, TResult>;
profileTransform?: ProfileTransform<TResult>;
signInResolver?: SignInResolver<TResult>;
signInResolverFactories?: Record<
string,
SignInResolverFactory<TResult, unknown>
>;
}): AuthProviderFactory {
return ctx => {
const signInResolver =
options.signInResolver ??
readDeclarativeSignInResolver({
config: ctx.config,
signInResolverFactories: options.signInResolverFactories ?? {},
});
if (!signInResolver) {
throw new Error(
`No sign-in resolver configured for proxy auth provider '${ctx.providerId}'`,
);
}
return createProxyAuthRouteHandlers<TResult>({
signInResolver,
config: ctx.config,
authenticator: options.authenticator,
resolverContext: ctx.resolverContext,
profileTransform: options.profileTransform,
});
};
}
@@ -0,0 +1,79 @@
/*
* Copyright 2020 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 { Request, Response } from 'express';
import { Config } from '@backstage/config';
import {
AuthProviderRouteHandlers,
AuthResolverContext,
ClientAuthResponse,
ProfileTransform,
SignInResolver,
} from '../types';
import { ProxyAuthenticator } from './types';
import { prepareBackstageIdentityResponse } from '../identity';
/** @public */
export interface ProxyAuthRouteHandlersOptions<TResult> {
authenticator: ProxyAuthenticator<any, TResult>;
config: Config;
resolverContext: AuthResolverContext;
signInResolver: SignInResolver<TResult>;
profileTransform?: ProfileTransform<TResult>;
}
/** @public */
export function createProxyAuthRouteHandlers<TResult>(
options: ProxyAuthRouteHandlersOptions<TResult>,
): AuthProviderRouteHandlers {
const { authenticator, config, resolverContext, signInResolver } = options;
const profileTransform =
options.profileTransform ?? authenticator.defaultProfileTransform;
const authenticatorCtx = authenticator.initialize({ config });
return {
async start(): Promise<void> {
throw new Error('Not implemented');
},
async frameHandler(): Promise<void> {
throw new Error('Not implemented');
},
async refresh(this: never, req: Request, res: Response): Promise<void> {
const { result } = await authenticator.authenticate(
{ req },
authenticatorCtx,
);
const { profile } = await profileTransform(result, resolverContext);
const identity = await signInResolver(
{ profile, result },
resolverContext,
);
const response: ClientAuthResponse<{}> = {
profile,
providerInfo: {},
backstageIdentity: prepareBackstageIdentityResponse(identity),
};
res.status(200).json(response);
},
};
}
+22
View File
@@ -0,0 +1,22 @@
/*
* 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.
*/
export { createProxyAuthenticator, type ProxyAuthenticator } from './types';
export { createProxyAuthProviderFactory } from './createProxyAuthProviderFactory';
export {
createProxyAuthRouteHandlers,
type ProxyAuthRouteHandlersOptions,
} from './createProxyRouteHandlers';
+34
View File
@@ -0,0 +1,34 @@
/*
* 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 { Request } from 'express';
import { ProfileTransform } from '../types';
export interface ProxyAuthenticator<TContext, TResult> {
defaultProfileTransform: ProfileTransform<TResult>;
initialize(ctx: { config: Config }): Promise<TContext>;
authenticate(
options: { req: Request },
ctx: TContext,
): Promise<{ result: TResult }>;
}
export function createProxyAuthenticator<TContext, TResult>(
authenticator: ProxyAuthenticator<TContext, TResult>,
): ProxyAuthenticator<TContext, TResult> {
return authenticator;
}