diff --git a/.changeset/breezy-planets-sparkle.md b/.changeset/breezy-planets-sparkle.md index 025becb2d6..eea9e5c6bf 100644 --- a/.changeset/breezy-planets-sparkle.md +++ b/.changeset/breezy-planets-sparkle.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-auth-backend-module-onelogin-provider': patch +'@backstage/plugin-auth-backend-module-onelogin-provider': minor --- -Initial changeset to introduce onelogin provider +Separate out the OneLogin provider into its own module diff --git a/.changeset/wild-coats-doubt.md b/.changeset/wild-coats-doubt.md new file mode 100644 index 0000000000..4e86911127 --- /dev/null +++ b/.changeset/wild-coats-doubt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Updated to use the new `@backstage/plugin-auth-backend-module-onelogin-provider` implementation diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index 77dd930a73..7322385e9b 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -268,6 +268,7 @@ Olausson Oldsberg onboarding Onboarding +onelogin OpenSearch OpenShift openssl diff --git a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts index 582b5a8282..d8f54e7e50 100644 --- a/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts +++ b/packages/core-app-api/src/apis/implementations/auth/onelogin/OneLoginAuth.ts @@ -76,7 +76,7 @@ export default class OneLoginAuth { oauthRequestApi, provider, environment, - defaultScopes: ['openid', 'email', 'profile'], + defaultScopes: ['openid', 'email', 'profile', 'offline_access'], scopeTransform(scopes) { return scopes.map(scope => { if (OIDC_SCOPES.has(scope)) { diff --git a/plugins/auth-backend-module-onelogin-provider/src/authenticator.ts b/plugins/auth-backend-module-onelogin-provider/src/authenticator.ts index f6ac3f55d5..ab1d4c3238 100644 --- a/plugins/auth-backend-module-onelogin-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-onelogin-provider/src/authenticator.ts @@ -58,7 +58,6 @@ export const oneLoginAuthenticator = createOAuthAuthenticator({ }, async start(input, helper) { - input.scope = 'openid email profile'; return helper.start(input, { accessType: 'offline', prompt: 'consent', diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 0797145855..ffdaf53fb3 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -57,6 +57,7 @@ "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^", "@backstage/plugin-auth-backend-module-oidc-provider": "workspace:^", "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^", + "@backstage/plugin-auth-backend-module-onelogin-provider": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@backstage/types": "workspace:^", diff --git a/plugins/auth-backend/src/providers/onelogin/provider.ts b/plugins/auth-backend/src/providers/onelogin/provider.ts index 0360a91a1c..ab5995da4c 100644 --- a/plugins/auth-backend/src/providers/onelogin/provider.ts +++ b/plugins/auth-backend/src/providers/onelogin/provider.ts @@ -14,156 +14,18 @@ * limitations under the License. */ -import { Strategy as OneLoginStrategy } from 'passport-onelogin-oauth'; -import express from 'express'; +import { oneLoginAuthenticator } from '@backstage/plugin-auth-backend-module-onelogin-provider'; import { - OAuthAdapter, - OAuthProviderOptions, - OAuthHandlers, - OAuthResponse, - OAuthEnvironmentHandler, - OAuthStartRequest, - encodeState, - OAuthRefreshRequest, - OAuthResult, -} from '../../lib/oauth'; -import passport from 'passport'; -import { - executeFrameHandlerStrategy, - executeRedirectStrategy, - executeRefreshTokenStrategy, - makeProfileInfo, - executeFetchUserProfileStrategy, - PassportDoneCallback, -} from '../../lib/passport'; -import { OAuthStartResponse, AuthHandler } from '../types'; -import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; -import { - AuthResolverContext, SignInResolver, + createOAuthProviderFactory, } from '@backstage/plugin-auth-node'; - -type PrivateInfo = { - refreshToken: string; -}; - -export type Options = OAuthProviderOptions & { - issuer: string; - signInResolver?: SignInResolver; - authHandler: AuthHandler; - resolverContext: AuthResolverContext; -}; - -export class OneLoginProvider implements OAuthHandlers { - private readonly _strategy: any; - private readonly signInResolver?: SignInResolver; - private readonly authHandler: AuthHandler; - private readonly resolverContext: AuthResolverContext; - - constructor(options: Options) { - this.signInResolver = options.signInResolver; - this.authHandler = options.authHandler; - this.resolverContext = options.resolverContext; - this._strategy = new OneLoginStrategy( - { - issuer: options.issuer, - clientID: options.clientId, - clientSecret: options.clientSecret, - callbackURL: options.callbackUrl, - passReqToCallback: false, - }, - ( - accessToken: any, - refreshToken: any, - params: any, - fullProfile: passport.Profile, - done: PassportDoneCallback, - ) => { - done( - undefined, - { - accessToken, - refreshToken, - params, - fullProfile, - }, - { - refreshToken, - }, - ); - }, - ); - } - async start(req: OAuthStartRequest): Promise { - return await executeRedirectStrategy(req, this._strategy, { - accessType: 'offline', - prompt: 'consent', - scope: 'openid', - state: encodeState(req.state), - }); - } - - async handler(req: express.Request) { - const { result, privateInfo } = await executeFrameHandlerStrategy< - OAuthResult, - PrivateInfo - >(req, this._strategy); - - return { - response: await this.handleResult(result), - refreshToken: privateInfo.refreshToken, - }; - } - - async refresh(req: OAuthRefreshRequest) { - const { accessToken, refreshToken, params } = - await executeRefreshTokenStrategy( - this._strategy, - req.refreshToken, - 'openid', - ); - - const fullProfile = await executeFetchUserProfileStrategy( - this._strategy, - accessToken, - ); - - return { - response: await this.handleResult({ - fullProfile, - params, - accessToken, - }), - refreshToken, - }; - } - - private async handleResult(result: OAuthResult) { - const { profile } = await this.authHandler(result, this.resolverContext); - - const response: OAuthResponse = { - providerInfo: { - idToken: result.params.id_token, - accessToken: result.accessToken, - scope: result.params.scope, - expiresInSeconds: result.params.expires_in, - }, - profile, - }; - - if (this.signInResolver) { - response.backstageIdentity = await this.signInResolver( - { - result, - profile, - }, - this.resolverContext, - ); - } - - return response; - } -} +import { + adaptLegacyOAuthHandler, + adaptLegacyOAuthSignInResolver, +} from '../../lib/legacy'; +import { OAuthResult } from '../../lib/oauth'; +import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; +import { AuthHandler } from '../types'; /** * Auth provider integration for OneLogin auth @@ -188,36 +50,10 @@ export const onelogin = createAuthProviderIntegration({ resolver: SignInResolver; }; }) { - return ({ providerId, globalConfig, config, resolverContext }) => - OAuthEnvironmentHandler.mapConfig(config, envConfig => { - const clientId = envConfig.getString('clientId'); - const clientSecret = envConfig.getString('clientSecret'); - const issuer = envConfig.getString('issuer'); - const customCallbackUrl = envConfig.getOptionalString('callbackUrl'); - const callbackUrl = - customCallbackUrl || - `${globalConfig.baseUrl}/${providerId}/handler/frame`; - - const authHandler: AuthHandler = options?.authHandler - ? options.authHandler - : async ({ fullProfile, params }) => ({ - profile: makeProfileInfo(fullProfile, params.id_token), - }); - - const provider = new OneLoginProvider({ - clientId, - clientSecret, - callbackUrl, - issuer, - authHandler, - signInResolver: options?.signIn?.resolver, - resolverContext, - }); - - return OAuthAdapter.fromConfig(globalConfig, provider, { - providerId, - callbackUrl, - }); - }); + return createOAuthProviderFactory({ + authenticator: oneLoginAuthenticator, + profileTransform: adaptLegacyOAuthHandler(options?.authHandler), + signInResolver: adaptLegacyOAuthSignInResolver(options?.signIn?.resolver), + }); }, }); diff --git a/yarn.lock b/yarn.lock index 452796c641..33dbd33246 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4688,7 +4688,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-auth-backend-module-onelogin-provider@workspace:plugins/auth-backend-module-onelogin-provider": +"@backstage/plugin-auth-backend-module-onelogin-provider@workspace:^, @backstage/plugin-auth-backend-module-onelogin-provider@workspace:plugins/auth-backend-module-onelogin-provider": version: 0.0.0-use.local resolution: "@backstage/plugin-auth-backend-module-onelogin-provider@workspace:plugins/auth-backend-module-onelogin-provider" dependencies: @@ -4776,6 +4776,7 @@ __metadata: "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "workspace:^" "@backstage/plugin-auth-backend-module-oidc-provider": "workspace:^" "@backstage/plugin-auth-backend-module-okta-provider": "workspace:^" + "@backstage/plugin-auth-backend-module-onelogin-provider": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" "@backstage/types": "workspace:^"