diff --git a/app-config.yaml b/app-config.yaml index 4321ef138c..01e2ff33fe 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -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: diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 903f6dc63c..7eeca59028 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 78db99c75c..e6ba56d2c3 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index e9246a30c0..1c2a822d82 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index d956cb2f44..d4455ac4d3 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index ed3bbba6ea..72cd76c4cd 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index cfae366f7e..db8e0cf313 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -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, diff --git a/plugins/auth-backend/src/providers/saml/provider.ts b/plugins/auth-backend/src/providers/saml/provider.ts index 1ccee1a9cb..56793d85f4 100644 --- a/plugins/auth-backend/src/providers/saml/provider.ts +++ b/plugins/auth-backend/src/providers/saml/provider.ts @@ -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); } diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 78cd4e1fe3..bdc12a382f 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -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 = { diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 70cd6d8f99..8ea1d412cb 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -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}`); } }