plugins/auth-backend: refactor providers for exporting with consistent casing

This commit is contained in:
Patrik Oldsberg
2020-08-20 11:15:18 +02:00
parent 02fa3ca781
commit b3fa6ffadd
10 changed files with 139 additions and 216 deletions
+2 -2
View File
@@ -105,10 +105,10 @@ auth:
clientSecret:
$secret:
env: AUTH_OAUTH2_CLIENT_SECRET
authorizationURL:
authorizationUrl:
$secret:
env: AUTH_OAUTH2_AUTH_URL
tokenURL:
tokenUrl:
$secret:
env: AUTH_OAUTH2_TOKEN_URL
auth0:
@@ -16,7 +16,7 @@
import express from 'express';
import passport from 'passport';
import Auth0Strategy, { Auth0StrategyOptionsWithRequest } from './strategy';
import Auth0Strategy from './strategy';
import { Logger } from 'winston';
import { TokenIssuer } from '../../identity';
import { OAuthProvider } from '../../lib/OAuthProvider';
@@ -33,6 +33,7 @@ import {
OAuthResponse,
PassportDoneCallback,
RedirectInfo,
OAuthProviderOptions,
} from '../types';
import { Config } from '@backstage/config';
@@ -40,12 +41,22 @@ type PrivateInfo = {
refreshToken: string;
};
export type Auth0AuthProviderOptions = OAuthProviderOptions & {
domain: string;
};
export class Auth0AuthProvider implements OAuthProviderHandlers {
private readonly _strategy: Auth0Strategy;
constructor(options: Auth0StrategyOptionsWithRequest) {
constructor(options: Auth0AuthProviderOptions) {
this._strategy = new Auth0Strategy(
options,
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
domain: options.domain,
passReqToCallback: false as true,
},
(
accessToken: any,
refreshToken: any,
@@ -144,36 +155,23 @@ export function createAuth0Provider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'auth0';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const domain = envConfig.getString('domain');
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const opts = {
clientID,
const provider = new Auth0AuthProvider({
clientId,
clientSecret,
callbackURL,
callbackUrl,
domain,
} as Auth0StrategyOptionsWithRequest;
});
if (!opts.clientID || !opts.clientSecret || !opts.domain) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize Auth0 auth provider, set AUTH_AUTH0_CLIENT_ID, AUTH_AUTH0_CLIENT_SECRET, and AUTH_AUTH0_DOMAIN env vars',
);
}
logger.warn(
'Auth0 auth provider disabled, set AUTH_AUTH0_CLIENT_ID, AUTH_AUTH0_CLIENT_SECRET, and AUTH_AUTH0_DOMAIN env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new Auth0AuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: true,
providerId,
tokenIssuer,
@@ -35,6 +35,12 @@ import { TokenIssuer } from '../../identity';
import passport from 'passport';
import { Config } from '@backstage/config';
export type GithubAuthProviderOptions = OAuthProviderOptions & {
tokenUrl?: string;
userProfileUrl?: string;
authorizationUrl?: string;
};
export class GithubAuthProvider implements OAuthProviderHandlers {
private readonly _strategy: GithubStrategy;
@@ -87,9 +93,16 @@ export class GithubAuthProvider implements OAuthProviderHandlers {
};
}
constructor(options: OAuthProviderOptions) {
constructor(options: GithubAuthProviderOptions) {
this._strategy = new GithubStrategy(
{ ...options },
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
tokenURL: options.tokenUrl,
userProfileURL: options.userProfileUrl,
authorizationURL: options.authorizationUrl,
},
(
accessToken: any,
_: any,
@@ -128,48 +141,36 @@ export function createGithubProvider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'github';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const enterpriseInstanceUrl = envConfig.getOptionalString(
'enterpriseInstanceUrl',
);
const authorizationURL = enterpriseInstanceUrl
const authorizationUrl = enterpriseInstanceUrl
? `${enterpriseInstanceUrl}/login/oauth/authorize`
: undefined;
const tokenURL = enterpriseInstanceUrl
const tokenUrl = enterpriseInstanceUrl
? `${enterpriseInstanceUrl}/login/oauth/access_token`
: undefined;
const userProfileURL = enterpriseInstanceUrl
const userProfileUrl = enterpriseInstanceUrl
? `${enterpriseInstanceUrl}/api/v3/user`
: undefined;
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const opts = {
clientID,
const provider = new GithubAuthProvider({
clientId,
clientSecret,
authorizationURL,
tokenURL,
userProfileURL,
callbackURL,
};
callbackUrl,
tokenUrl,
userProfileUrl,
authorizationUrl,
});
if (!opts.clientID || !opts.clientSecret) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize Github auth provider, set AUTH_GITHUB_CLIENT_ID and AUTH_GITHUB_CLIENT_SECRET env vars',
);
}
logger.warn(
'Github auth provider disabled, set AUTH_GITHUB_CLIENT_ID and AUTH_GITHUB_CLIENT_SECRET env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new GithubAuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: true,
persistScopes: true,
providerId,
@@ -35,6 +35,10 @@ import { TokenIssuer } from '../../identity';
import passport from 'passport';
import { Config } from '@backstage/config';
export type GitlabAuthProviderOptions = OAuthProviderOptions & {
baseUrl: string;
};
export class GitlabAuthProvider implements OAuthProviderHandlers {
private readonly _strategy: GitlabStrategy;
@@ -96,9 +100,14 @@ export class GitlabAuthProvider implements OAuthProviderHandlers {
};
}
constructor(options: OAuthProviderOptions) {
constructor(options: GitlabAuthProviderOptions) {
this._strategy = new GitlabStrategy(
{ ...options },
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
baseURL: options.baseUrl,
},
(
accessToken: any,
_: any,
@@ -135,36 +144,24 @@ export function createGitlabProvider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'gitlab';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const audience = envConfig.getString('audience');
const baseURL = audience || 'https://gitlab.com';
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const baseUrl = audience || 'https://gitlab.com';
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const opts = {
clientID,
const provider = new GitlabAuthProvider({
clientId,
clientSecret,
callbackURL,
baseURL,
};
callbackUrl,
baseUrl,
});
if (!opts.clientID || !opts.clientSecret) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize Gitlab auth provider, set AUTH_GITLAB_CLIENT_ID and AUTH_GITLAB_CLIENT_SECRET env vars',
);
}
logger.warn(
'Gitlab auth provider disabled, set AUTH_GITLAB_CLIENT_ID and AUTH_GITLAB_CLIENT_SECRET env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new GitlabAuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: true,
providerId,
tokenIssuer,
@@ -47,9 +47,14 @@ export class GoogleAuthProvider implements OAuthProviderHandlers {
constructor(options: OAuthProviderOptions) {
// TODO: throw error if env variables not set?
this._strategy = new GoogleStrategy(
// We need passReqToCallback set to false to get params, but there's
// no matching type signature for that, so instead behold this beauty
{ ...options, passReqToCallback: false as true },
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
// We need passReqToCallback set to false to get params, but there's
// no matching type signature for that, so instead behold this beauty
passReqToCallback: false as true,
},
(
accessToken: any,
refreshToken: any,
@@ -147,33 +152,21 @@ export function createGoogleProvider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'google';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const opts = {
clientID,
const provider = new GoogleAuthProvider({
clientId,
clientSecret,
callbackURL,
};
callbackUrl,
});
if (!opts.clientID || !opts.clientSecret) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize Google auth provider, set AUTH_GOOGLE_CLIENT_ID and AUTH_GOOGLE_CLIENT_SECRET env vars',
);
}
logger.warn(
'Google auth provider disabled, set AUTH_GOOGLE_CLIENT_ID and AUTH_GOOGLE_CLIENT_SECRET env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new GoogleAuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: false,
providerId,
tokenIssuer,
@@ -42,8 +42,8 @@ type PrivateInfo = {
};
export type OAuth2AuthProviderOptions = OAuthProviderOptions & {
authorizationURL: string;
tokenURL: string;
authorizationUrl: string;
tokenUrl: string;
};
export class OAuth2AuthProvider implements OAuthProviderHandlers {
@@ -51,7 +51,14 @@ export class OAuth2AuthProvider implements OAuthProviderHandlers {
constructor(options: OAuth2AuthProviderOptions) {
this._strategy = new OAuth2Strategy(
{ ...options, passReqToCallback: false as true },
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
authorizationURL: options.authorizationUrl,
tokenURL: options.tokenUrl,
passReqToCallback: false as true,
},
(
accessToken: any,
refreshToken: any,
@@ -150,42 +157,25 @@ export function createOAuth2Provider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'oauth2';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const authorizationURL = envConfig.getString('authorizationURL');
const tokenURL = envConfig.getString('tokenURL');
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const authorizationUrl = envConfig.getString('authorizationUrl');
const tokenUrl = envConfig.getString('tokenUrl');
const opts = {
clientID,
const provider = new OAuth2AuthProvider({
clientId,
clientSecret,
callbackURL,
authorizationURL,
tokenURL,
};
callbackUrl,
authorizationUrl,
tokenUrl,
});
if (
!opts.clientID ||
!opts.clientSecret ||
!opts.authorizationURL ||
!opts.tokenURL
) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize OAuth2 auth provider, set AUTH_OAUTH2_CLIENT_ID, AUTH_OAUTH2_CLIENT_SECRET, AUTH_OAUTH2_AUTH_URL, and AUTH_OAUTH2_TOKEN_URL env vars',
);
}
logger.warn(
'OAuth2 auth provider disabled, set AUTH_OAUTH2_CLIENT_ID, AUTH_OAUTH2_CLIENT_SECRET, AUTH_OAUTH2_AUTH_URL, and AUTH_OAUTH2_TOKEN_URL env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new OAuth2AuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: false,
providerId,
tokenIssuer,
@@ -41,6 +41,10 @@ type PrivateInfo = {
refreshToken: string;
};
export type OktaAuthProviderOptions = OAuthProviderOptions & {
audience: string;
};
export class OktaAuthProvider implements OAuthProviderHandlers {
private readonly _strategy: any;
@@ -61,11 +65,14 @@ export class OktaAuthProvider implements OAuthProviderHandlers {
},
};
constructor(options: OAuthProviderOptions) {
constructor(options: OktaAuthProviderOptions) {
this._strategy = new OktaStrategy(
{
clientID: options.clientId,
clientSecret: options.clientSecret,
callbackURL: options.callbackUrl,
audience: options.audience,
passReqToCallback: false as true,
...options,
store: this._store,
response_type: 'code',
},
@@ -167,35 +174,23 @@ export function createOktaProvider(
config: AuthProviderConfig,
_: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const providerId = 'okta';
const clientID = envConfig.getString('clientId');
const clientId = envConfig.getString('clientId');
const clientSecret = envConfig.getString('clientSecret');
const audience = envConfig.getString('audience');
const callbackURL = `${config.baseUrl}/${providerId}/handler/frame`;
const callbackUrl = `${config.baseUrl}/${providerId}/handler/frame`;
const opts = {
const provider = new OktaAuthProvider({
audience,
clientID,
clientId,
clientSecret,
callbackURL,
};
callbackUrl,
});
if (!opts.clientID || !opts.clientSecret || !opts.audience) {
if (process.env.NODE_ENV !== 'development') {
throw new Error(
'Failed to initialize Okta auth provider, set AUTH_OKTA_CLIENT_ID, AUTH_OKTA_CLIENT_SECRET, and AUTH_OKTA_AUDIENCE env vars',
);
}
logger.warn(
'Okta auth provider disabled, set AUTH_OKTA_CLIENT_ID, AUTH_OKTA_CLIENT_SECRET, and AUTH_OKTA_AUDIENCE env vars to enable',
);
return undefined;
}
return OAuthProvider.fromConfig(config, new OktaAuthProvider(opts), {
return OAuthProvider.fromConfig(config, provider, {
disableRefresh: false,
providerId,
tokenIssuer,
@@ -123,7 +123,7 @@ export function createSamlProvider(
_authProviderConfig: AuthProviderConfig,
_env: string,
envConfig: Config,
logger: Logger,
_logger: Logger,
tokenIssuer: TokenIssuer,
) {
const entryPoint = envConfig.getString('entryPoint');
@@ -135,11 +135,5 @@ export function createSamlProvider(
tokenIssuer,
};
if (!opts.entryPoint || !opts.issuer) {
logger.warn(
'SAML auth provider disabled, set entryPoint and entryPoint in saml auth config to enable',
);
return undefined;
}
return new SamlAuthProvider(opts);
}
+2 -53
View File
@@ -25,7 +25,7 @@ export type OAuthProviderOptions = {
/**
* Client ID of the auth provider.
*/
clientID: string;
clientId: string;
/**
* Client Secret of the auth provider.
*/
@@ -33,58 +33,7 @@ export type OAuthProviderOptions = {
/**
* Callback URL to be passed to the auth provider to redirect to after the user signs in.
*/
callbackURL: string;
};
export type GenericOAuth2ProviderOptions = OAuthProviderOptions & {
authorizationURL: string;
tokenURL: string;
};
export type OAuthProviderConfig = {
/**
* Cookies can be marked with a secure flag to send cookies only when the request
* is over an encrypted channel (HTTPS).
*
* For development environment we don't mark the cookie as secure since we serve
* localhost over HTTP.
*/
secure: boolean;
/**
* The protocol://domain[:port] where the app (frontend) is hosted. This is used to post messages back
* to the window that initiates an auth request.
*/
appOrigin: string;
/**
* Client ID of the auth provider.
*/
clientId: string;
/**
* Client Secret of the auth provider.
*/
clientSecret: string;
/**
* The location of the OAuth Authorization Server
*/
audience?: string;
};
export type GenericOAuth2ProviderConfig = OAuthProviderConfig & {
authorizationURL: string;
tokenURL: string;
};
export type EnvironmentProviderConfig = {
/**
* key, values are environment names and OAuthProviderConfigs
*
* For e.g
* {
* development: DevelopmentOAuthProviderConfig
* production: ProductionOAuthProviderConfig
* }
*/
[key: string]: OAuthProviderConfig;
callbackUrl: string;
};
export type AuthProviderConfig = {
+7 -1
View File
@@ -72,7 +72,13 @@ export async function createRouter(
);
router.use(`/${providerId}`, providerRouter);
} catch (e) {
logger.error(e.message);
if (process.env.NODE_ENV !== 'development') {
throw new Error(
`Failed to initialize ${providerId} auth provider, ${e.message}`,
);
}
logger.warn(`Skipping ${providerId} auth provider, ${e.message}`);
}
}