@backstage/plugin-auth-backend 0.3.24 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # @backstage/plugin-auth-backend
2
2
 
3
+ ## 0.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 4c3eea7788: Bitbucket Cloud authentication - based on the existing GitHub authentication + changes around BB apis and updated scope.
8
+
9
+ - BitbucketAuth added to core-app-api.
10
+ - Bitbucket provider added to plugin-auth-backend.
11
+ - Cosmetic entry for Bitbucket connection in user-settings Authentication Providers tab.
12
+
13
+ - Updated dependencies
14
+ - @backstage/test-utils@0.1.18
15
+ - @backstage/catalog-model@0.9.4
16
+ - @backstage/backend-common@0.9.6
17
+ - @backstage/catalog-client@0.5.0
18
+
19
+ ## 0.4.2
20
+
21
+ ### Patch Changes
22
+
23
+ - 88622e6422: Allow users to override callback url of GitHub provider
24
+ - c46396ebb0: Update OAuth refresh handler to pass updated refresh token to ensure cookie is updated with new value.
25
+ - Updated dependencies
26
+ - @backstage/backend-common@0.9.5
27
+
28
+ ## 0.4.1
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies
33
+ - @backstage/catalog-client@0.4.0
34
+ - @backstage/catalog-model@0.9.3
35
+ - @backstage/backend-common@0.9.4
36
+ - @backstage/config@0.1.10
37
+
38
+ ## 0.4.0
39
+
40
+ ### Minor Changes
41
+
42
+ - 19f45179a5: Bump `passport-saml` to version 3. This is a breaking change, in that it [now requires](https://github.com/node-saml/passport-saml/pull/548) the `auth.saml.cert` parameter to be set. If you are not using SAML auth, you can ignore this.
43
+
44
+ To update your settings, add something similar to the following to your app-config:
45
+
46
+ ```yaml
47
+ auth:
48
+ saml:
49
+ # ... other settings ...
50
+ cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W=='
51
+ ```
52
+
53
+ For more information, see the [library README](https://github.com/node-saml/passport-saml#security-and-signatures).
54
+
55
+ ### Patch Changes
56
+
57
+ - 560d6810f0: Fix a bug preventing an access token to be refreshed a second time with the GitLab provider.
58
+ - de5717872d: Use a more informative error message if the configured OIDC identity provider does not provide a `userinfo_endpoint` in its metadata.
59
+ - Updated dependencies
60
+ - @backstage/backend-common@0.9.3
61
+
3
62
  ## 0.3.24
4
63
 
5
64
  ### Patch Changes
package/config.d.ts CHANGED
@@ -48,7 +48,7 @@ export interface Config {
48
48
  entryPoint: string;
49
49
  logoutUrl?: string;
50
50
  issuer: string;
51
- cert?: string;
51
+ cert: string;
52
52
  privateKey?: string;
53
53
  decryptionPvk?: string;
54
54
  signatureAlgorithm?: 'sha256' | 'sha512';
package/dist/index.cjs.js CHANGED
@@ -18,6 +18,7 @@ var passportMicrosoft = require('passport-microsoft');
18
18
  var got = require('got');
19
19
  var OAuth2Strategy = require('passport-oauth2');
20
20
  var passportOktaOauth = require('passport-okta-oauth');
21
+ var passportBitbucketOauth2 = require('passport-bitbucket-oauth2');
21
22
  var openidClient = require('openid-client');
22
23
  var passportSaml = require('passport-saml');
23
24
  var passportOneloginOauth = require('passport-onelogin-oauth');
@@ -285,7 +286,7 @@ const postMessageResponse = (res, appOrigin, response) => {
285
286
  (window.opener || window.parent).postMessage(JSON.parse(authResponse), origin);
286
287
  setTimeout(() => {
287
288
  window.close();
288
- }, 100); // same as the interval of the core-api lib/loginPopup.ts (to address race conditions)
289
+ }, 100); // same as the interval of the core-app-api lib/loginPopup.ts (to address race conditions)
289
290
  `;
290
291
  const hash = crypto__default['default'].createHash("sha256").update(script).digest("base64");
291
292
  res.setHeader("Content-Type", "text/html");
@@ -632,10 +633,11 @@ const createGithubProvider = (options) => {
632
633
  const clientId = envConfig.getString("clientId");
633
634
  const clientSecret = envConfig.getString("clientSecret");
634
635
  const enterpriseInstanceUrl = envConfig.getOptionalString("enterpriseInstanceUrl");
636
+ const customCallbackUrl = envConfig.getOptionalString("callbackUrl");
635
637
  const authorizationUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/authorize` : void 0;
636
638
  const tokenUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/login/oauth/access_token` : void 0;
637
639
  const userProfileUrl = enterpriseInstanceUrl ? `${enterpriseInstanceUrl}/api/v3/user` : void 0;
638
- const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
640
+ const callbackUrl = customCallbackUrl || `${globalConfig.baseUrl}/${providerId}/handler/frame`;
639
641
  const catalogIdentityClient = new CatalogIdentityClient({
640
642
  catalogApi,
641
643
  tokenIssuer
@@ -738,6 +740,7 @@ class GitlabAuthProvider {
738
740
  providerInfo: {
739
741
  idToken: result.params.id_token,
740
742
  accessToken: result.accessToken,
743
+ refreshToken: result.refreshToken,
741
744
  scope: result.params.scope,
742
745
  expiresInSeconds: result.params.expires_in
743
746
  },
@@ -1174,7 +1177,8 @@ class OAuth2AuthProvider {
1174
1177
  idToken: result.params.id_token,
1175
1178
  accessToken: result.accessToken,
1176
1179
  scope: result.params.scope,
1177
- expiresInSeconds: result.params.expires_in
1180
+ expiresInSeconds: result.params.expires_in,
1181
+ refreshToken: result.refreshToken
1178
1182
  },
1179
1183
  profile
1180
1184
  };
@@ -1407,6 +1411,145 @@ const createOktaProvider = (_options) => {
1407
1411
  });
1408
1412
  };
1409
1413
 
1414
+ class BitbucketAuthProvider {
1415
+ constructor(options) {
1416
+ this.signInResolver = options.signInResolver;
1417
+ this.authHandler = options.authHandler;
1418
+ this.tokenIssuer = options.tokenIssuer;
1419
+ this.catalogIdentityClient = options.catalogIdentityClient;
1420
+ this.logger = options.logger;
1421
+ this._strategy = new passportBitbucketOauth2.Strategy({
1422
+ clientID: options.clientId,
1423
+ clientSecret: options.clientSecret,
1424
+ callbackURL: options.callbackUrl,
1425
+ passReqToCallback: false
1426
+ }, (accessToken, refreshToken, params, fullProfile, done) => {
1427
+ done(void 0, {
1428
+ fullProfile,
1429
+ params,
1430
+ accessToken,
1431
+ refreshToken
1432
+ }, {
1433
+ refreshToken
1434
+ });
1435
+ });
1436
+ }
1437
+ async start(req) {
1438
+ return await executeRedirectStrategy(req, this._strategy, {
1439
+ accessType: "offline",
1440
+ prompt: "consent",
1441
+ scope: req.scope,
1442
+ state: encodeState(req.state)
1443
+ });
1444
+ }
1445
+ async handler(req) {
1446
+ const {result, privateInfo} = await executeFrameHandlerStrategy(req, this._strategy);
1447
+ return {
1448
+ response: await this.handleResult(result),
1449
+ refreshToken: privateInfo.refreshToken
1450
+ };
1451
+ }
1452
+ async refresh(req) {
1453
+ const {accessToken, params} = await executeRefreshTokenStrategy(this._strategy, req.refreshToken, req.scope);
1454
+ const fullProfile = await executeFetchUserProfileStrategy(this._strategy, accessToken);
1455
+ return this.handleResult({
1456
+ fullProfile,
1457
+ params,
1458
+ accessToken,
1459
+ refreshToken: req.refreshToken
1460
+ });
1461
+ }
1462
+ async handleResult(result) {
1463
+ result.fullProfile.avatarUrl = result.fullProfile._json.links.avatar.href;
1464
+ const {profile} = await this.authHandler(result);
1465
+ const response = {
1466
+ providerInfo: {
1467
+ idToken: result.params.id_token,
1468
+ accessToken: result.accessToken,
1469
+ scope: result.params.scope,
1470
+ expiresInSeconds: result.params.expires_in
1471
+ },
1472
+ profile
1473
+ };
1474
+ if (this.signInResolver) {
1475
+ response.backstageIdentity = await this.signInResolver({
1476
+ result,
1477
+ profile
1478
+ }, {
1479
+ tokenIssuer: this.tokenIssuer,
1480
+ catalogIdentityClient: this.catalogIdentityClient,
1481
+ logger: this.logger
1482
+ });
1483
+ }
1484
+ return response;
1485
+ }
1486
+ }
1487
+ const bitbucketUsernameSignInResolver = async (info, ctx) => {
1488
+ const {result} = info;
1489
+ if (!result.fullProfile.username) {
1490
+ throw new Error("Bitbucket profile contained no Username");
1491
+ }
1492
+ const entity = await ctx.catalogIdentityClient.findUser({
1493
+ annotations: {
1494
+ "bitbucket.org/username": result.fullProfile.username
1495
+ }
1496
+ });
1497
+ const claims = getEntityClaims(entity);
1498
+ const token = await ctx.tokenIssuer.issueToken({claims});
1499
+ return {id: entity.metadata.name, entity, token};
1500
+ };
1501
+ const bitbucketUserIdSignInResolver = async (info, ctx) => {
1502
+ const {result} = info;
1503
+ if (!result.fullProfile.id) {
1504
+ throw new Error("Bitbucket profile contained no User ID");
1505
+ }
1506
+ const entity = await ctx.catalogIdentityClient.findUser({
1507
+ annotations: {
1508
+ "bitbucket.org/user-id": result.fullProfile.id
1509
+ }
1510
+ });
1511
+ const claims = getEntityClaims(entity);
1512
+ const token = await ctx.tokenIssuer.issueToken({claims});
1513
+ return {id: entity.metadata.name, entity, token};
1514
+ };
1515
+ const createBitbucketProvider = (options) => {
1516
+ return ({
1517
+ providerId,
1518
+ globalConfig,
1519
+ config,
1520
+ tokenIssuer,
1521
+ catalogApi,
1522
+ logger
1523
+ }) => OAuthEnvironmentHandler.mapConfig(config, (envConfig) => {
1524
+ var _a;
1525
+ const clientId = envConfig.getString("clientId");
1526
+ const clientSecret = envConfig.getString("clientSecret");
1527
+ const callbackUrl = `${globalConfig.baseUrl}/${providerId}/handler/frame`;
1528
+ const catalogIdentityClient = new CatalogIdentityClient({
1529
+ catalogApi,
1530
+ tokenIssuer
1531
+ });
1532
+ const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({fullProfile, params}) => ({
1533
+ profile: makeProfileInfo(fullProfile, params.id_token)
1534
+ });
1535
+ const provider = new BitbucketAuthProvider({
1536
+ clientId,
1537
+ clientSecret,
1538
+ callbackUrl,
1539
+ signInResolver: (_a = options == null ? void 0 : options.signIn) == null ? void 0 : _a.resolver,
1540
+ authHandler,
1541
+ tokenIssuer,
1542
+ catalogIdentityClient,
1543
+ logger
1544
+ });
1545
+ return OAuthAdapter.fromConfig(globalConfig, provider, {
1546
+ disableRefresh: false,
1547
+ providerId,
1548
+ tokenIssuer
1549
+ });
1550
+ });
1551
+ };
1552
+
1410
1553
  class OidcAuthProvider {
1411
1554
  constructor(options) {
1412
1555
  this.implementation = this.setupStrategy(options);
@@ -1483,6 +1626,9 @@ class OidcAuthProvider {
1483
1626
  client,
1484
1627
  passReqToCallback: false
1485
1628
  }, (tokenset, userinfo, done) => {
1629
+ if (typeof done !== "function") {
1630
+ throw new Error("OIDC IdP must provide a userinfo_endpoint in the metadata response");
1631
+ }
1486
1632
  done(void 0, {tokenset, userinfo}, {
1487
1633
  refreshToken: tokenset.refresh_token
1488
1634
  });
@@ -1573,13 +1719,13 @@ class SamlAuthProvider {
1573
1719
  }
1574
1720
  }
1575
1721
  const createSamlProvider = (_options) => {
1576
- return ({providerId, globalConfig, config, tokenIssuer, logger}) => {
1722
+ return ({providerId, globalConfig, config, tokenIssuer}) => {
1577
1723
  const opts = {
1578
1724
  callbackUrl: `${globalConfig.baseUrl}/${providerId}/handler/frame`,
1579
1725
  entryPoint: config.getString("entryPoint"),
1580
1726
  logoutUrl: config.getOptionalString("logoutUrl"),
1581
1727
  issuer: config.getString("issuer"),
1582
- cert: config.getOptionalString("cert"),
1728
+ cert: config.getString("cert"),
1583
1729
  privateCert: config.getOptionalString("privateKey"),
1584
1730
  decryptionPvk: config.getOptionalString("decryptionPvk"),
1585
1731
  signatureAlgorithm: config.getOptionalString("signatureAlgorithm"),
@@ -1588,10 +1734,6 @@ const createSamlProvider = (_options) => {
1588
1734
  tokenIssuer,
1589
1735
  appUrl: globalConfig.appUrl
1590
1736
  };
1591
- if (!opts.cert) {
1592
- logger.warn('SamlAuthProvider was initialized without a cert configuration parameter. This will soon be required by the underlying passport-saml library, which may soon lead to failures to start the auth backend. Please add an "auth.saml.cert" config parameter.');
1593
- delete opts.cert;
1594
- }
1595
1737
  return new SamlAuthProvider(opts);
1596
1738
  };
1597
1739
  };
@@ -1863,7 +2005,8 @@ const factories = {
1863
2005
  oauth2: createOAuth2Provider(),
1864
2006
  oidc: createOidcProvider(),
1865
2007
  onelogin: createOneLoginProvider(),
1866
- awsalb: createAwsAlbProvider()
2008
+ awsalb: createAwsAlbProvider(),
2009
+ bitbucket: createBitbucketProvider()
1867
2010
  };
1868
2011
 
1869
2012
  function createOidcRouter(options) {
@@ -2187,6 +2330,9 @@ function createOriginFilter(config) {
2187
2330
  exports.IdentityClient = IdentityClient;
2188
2331
  exports.OAuthAdapter = OAuthAdapter;
2189
2332
  exports.OAuthEnvironmentHandler = OAuthEnvironmentHandler;
2333
+ exports.bitbucketUserIdSignInResolver = bitbucketUserIdSignInResolver;
2334
+ exports.bitbucketUsernameSignInResolver = bitbucketUsernameSignInResolver;
2335
+ exports.createBitbucketProvider = createBitbucketProvider;
2190
2336
  exports.createGithubProvider = createGithubProvider;
2191
2337
  exports.createGitlabProvider = createGitlabProvider;
2192
2338
  exports.createGoogleProvider = createGoogleProvider;