@backstage/plugin-auth-backend 0.18.2-next.2 → 0.18.2-next.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,33 @@
1
1
  # @backstage/plugin-auth-backend
2
2
 
3
+ ## 0.18.2-next.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 475abd1dc3f: The `microsoft` (i.e. Azure) auth provider now supports negotiating tokens for
8
+ Azure resources besides Microsoft Graph (e.g. AKS, Virtual Machines, Machine
9
+ Learning Services, etc.). When the `/frame/handler` endpoint is called with an
10
+ authorization code for a non-Microsoft Graph scope, the user profile will not be
11
+ fetched. Similarly no user profile or photo data will be fetched by the backend
12
+ if the `/refresh` endpoint is called with the `scope` query parameter strictly
13
+ containing scopes for resources besides Microsoft Graph.
14
+
15
+ Furthermore, the `offline_access` scope will be requested by default, even when
16
+ it is not mentioned in the argument to `getAccessToken`. This means that any
17
+ Azure access token can be automatically refreshed, even if the user has not
18
+ signed in via Azure.
19
+
20
+ - 6a900951336: Add common identify resolvers for `oidc` auth provider.
21
+ - a0ef1ec7349: Export Azure Easy Auth provider so it can actually be used.
22
+ - Updated dependencies
23
+ - @backstage/catalog-model@1.3.0-next.0
24
+ - @backstage/backend-common@0.18.4-next.2
25
+ - @backstage/catalog-client@1.4.1-next.1
26
+ - @backstage/config@1.0.7
27
+ - @backstage/errors@1.1.5
28
+ - @backstage/types@1.0.2
29
+ - @backstage/plugin-auth-node@0.2.13-next.2
30
+
3
31
  ## 0.18.2-next.2
4
32
 
5
33
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -1872,6 +1872,11 @@ const google = createAuthProviderIntegration({
1872
1872
  const BACKSTAGE_SESSION_EXPIRATION = 3600;
1873
1873
  class MicrosoftAuthProvider {
1874
1874
  constructor(options) {
1875
+ this.skipUserProfile = (accessToken) => {
1876
+ const { aud, scp } = jose.decodeJwt(accessToken);
1877
+ const hasGraphReadScope = aud === "00000003-0000-0000-c000-000000000000" && scp.split(" ").map((s) => s.toLowerCase()).includes("user.read");
1878
+ return !hasGraphReadScope;
1879
+ };
1875
1880
  this.signInResolver = options.signInResolver;
1876
1881
  this.authHandler = options.authHandler;
1877
1882
  this.logger = options.logger;
@@ -1883,7 +1888,10 @@ class MicrosoftAuthProvider {
1883
1888
  callbackURL: options.callbackUrl,
1884
1889
  authorizationURL: options.authorizationUrl,
1885
1890
  tokenURL: options.tokenUrl,
1886
- passReqToCallback: false
1891
+ passReqToCallback: false,
1892
+ skipUserProfile: (accessToken, done) => {
1893
+ done(null, this.skipUserProfile(accessToken));
1894
+ }
1887
1895
  },
1888
1896
  (accessToken, refreshToken, params, fullProfile, done) => {
1889
1897
  done(void 0, { fullProfile, accessToken, params }, { refreshToken });
@@ -1909,43 +1917,46 @@ class MicrosoftAuthProvider {
1909
1917
  req.refreshToken,
1910
1918
  req.scope
1911
1919
  );
1912
- const fullProfile = await executeFetchUserProfileStrategy(
1913
- this._strategy,
1914
- accessToken
1915
- );
1916
1920
  return {
1917
1921
  response: await this.handleResult({
1918
- fullProfile,
1919
1922
  params,
1920
- accessToken
1923
+ accessToken,
1924
+ ...!this.skipUserProfile(accessToken) && {
1925
+ fullProfile: await executeFetchUserProfileStrategy(
1926
+ this._strategy,
1927
+ accessToken
1928
+ )
1929
+ }
1921
1930
  }),
1922
1931
  refreshToken
1923
1932
  };
1924
1933
  }
1925
1934
  async handleResult(result) {
1926
- const photo = await this.getUserPhoto(result.accessToken);
1927
- result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1928
- const { profile } = await this.authHandler(result, this.resolverContext);
1935
+ let profile = {};
1936
+ if (result.fullProfile) {
1937
+ const photo = await this.getUserPhoto(result.accessToken);
1938
+ result.fullProfile.photos = photo ? [{ value: photo }] : void 0;
1939
+ ({ profile } = await this.authHandler(
1940
+ result,
1941
+ this.resolverContext
1942
+ ));
1943
+ }
1929
1944
  const expiresInSeconds = result.params.expires_in === void 0 ? BACKSTAGE_SESSION_EXPIRATION : Math.min(result.params.expires_in, BACKSTAGE_SESSION_EXPIRATION);
1930
- const response = {
1945
+ return {
1931
1946
  providerInfo: {
1932
- idToken: result.params.id_token,
1933
1947
  accessToken: result.accessToken,
1934
1948
  scope: result.params.scope,
1935
- expiresInSeconds
1949
+ expiresInSeconds,
1950
+ ...{ idToken: result.params.id_token }
1936
1951
  },
1937
- profile
1952
+ profile,
1953
+ ...result.fullProfile && this.signInResolver && {
1954
+ backstageIdentity: await this.signInResolver(
1955
+ { result, profile },
1956
+ this.resolverContext
1957
+ )
1958
+ }
1938
1959
  };
1939
- if (this.signInResolver) {
1940
- response.backstageIdentity = await this.signInResolver(
1941
- {
1942
- result,
1943
- profile
1944
- },
1945
- this.resolverContext
1946
- );
1947
- }
1948
- return response;
1949
1960
  }
1950
1961
  async getUserPhoto(accessToken) {
1951
1962
  try {
@@ -1979,7 +1990,7 @@ const microsoft = createAuthProviderIntegration({
1979
1990
  const authorizationUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`;
1980
1991
  const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
1981
1992
  const authHandler = (options == null ? void 0 : options.authHandler) ? options.authHandler : async ({ fullProfile, params }) => ({
1982
- profile: makeProfileInfo(fullProfile, params.id_token)
1993
+ profile: makeProfileInfo(fullProfile != null ? fullProfile : {}, params.id_token)
1983
1994
  });
1984
1995
  const provider = new MicrosoftAuthProvider({
1985
1996
  clientId,
@@ -2382,6 +2393,16 @@ const oidc = createAuthProviderIntegration({
2382
2393
  callbackUrl
2383
2394
  });
2384
2395
  });
2396
+ },
2397
+ resolvers: {
2398
+ /**
2399
+ * Looks up the user by matching their email local part to the entity name.
2400
+ */
2401
+ emailLocalPartMatchingUserEntityName: () => commonByEmailLocalPartResolver,
2402
+ /**
2403
+ * Looks up the user by matching their email to the entity email.
2404
+ */
2405
+ emailMatchingUserEntityProfileEmail: () => commonByEmailResolver
2385
2406
  }
2386
2407
  });
2387
2408
 
@@ -2934,6 +2955,104 @@ const bitbucketServer = createAuthProviderIntegration({
2934
2955
  }
2935
2956
  });
2936
2957
 
2958
+ const ID_TOKEN_HEADER = "x-ms-token-aad-id-token";
2959
+ const ACCESS_TOKEN_HEADER = "x-ms-token-aad-access-token";
2960
+ class EasyAuthAuthProvider {
2961
+ constructor(options) {
2962
+ this.authHandler = options.authHandler;
2963
+ this.signInResolver = options.signInResolver;
2964
+ this.resolverContext = options.resolverContext;
2965
+ }
2966
+ frameHandler() {
2967
+ return Promise.resolve(void 0);
2968
+ }
2969
+ async refresh(req, res) {
2970
+ const result = await this.getResult(req);
2971
+ const response = await this.handleResult(result);
2972
+ res.json(response);
2973
+ }
2974
+ start() {
2975
+ return Promise.resolve(void 0);
2976
+ }
2977
+ async getResult(req) {
2978
+ const idToken = req.header(ID_TOKEN_HEADER);
2979
+ const accessToken = req.header(ACCESS_TOKEN_HEADER);
2980
+ if (idToken === void 0) {
2981
+ throw new errors.AuthenticationError(`Missing ${ID_TOKEN_HEADER} header`);
2982
+ }
2983
+ return {
2984
+ fullProfile: this.idTokenToProfile(idToken),
2985
+ accessToken
2986
+ };
2987
+ }
2988
+ idTokenToProfile(idToken) {
2989
+ const claims = jose.decodeJwt(idToken);
2990
+ if (claims.ver !== "2.0") {
2991
+ throw new Error("id_token is not version 2.0 ");
2992
+ }
2993
+ return {
2994
+ id: claims.oid,
2995
+ displayName: claims.name,
2996
+ provider: "easyauth",
2997
+ emails: [{ value: claims.email }],
2998
+ username: claims.preferred_username
2999
+ };
3000
+ }
3001
+ async handleResult(result) {
3002
+ const { profile } = await this.authHandler(result, this.resolverContext);
3003
+ const backstageIdentity = await this.signInResolver(
3004
+ {
3005
+ result,
3006
+ profile
3007
+ },
3008
+ this.resolverContext
3009
+ );
3010
+ return {
3011
+ providerInfo: {
3012
+ accessToken: result.accessToken
3013
+ },
3014
+ backstageIdentity: prepareBackstageIdentityResponse(backstageIdentity),
3015
+ profile
3016
+ };
3017
+ }
3018
+ }
3019
+ const easyAuth = createAuthProviderIntegration({
3020
+ create(options) {
3021
+ return ({ resolverContext }) => {
3022
+ var _a;
3023
+ validateAppServiceConfiguration(process.env);
3024
+ if ((options == null ? void 0 : options.signIn.resolver) === void 0) {
3025
+ throw new Error(
3026
+ "SignInResolver is required to use this authentication provider"
3027
+ );
3028
+ }
3029
+ const authHandler = (_a = options.authHandler) != null ? _a : async ({ fullProfile }) => ({
3030
+ profile: makeProfileInfo(fullProfile)
3031
+ });
3032
+ return new EasyAuthAuthProvider({
3033
+ signInResolver: options.signIn.resolver,
3034
+ authHandler,
3035
+ resolverContext
3036
+ });
3037
+ };
3038
+ }
3039
+ });
3040
+ function validateAppServiceConfiguration(env) {
3041
+ var _a, _b, _c;
3042
+ if (env.WEBSITE_SKU === void 0) {
3043
+ throw new Error("Backstage is not running on Azure App Services");
3044
+ }
3045
+ if (((_a = env.WEBSITE_AUTH_ENABLED) == null ? void 0 : _a.toLowerCase()) !== "true") {
3046
+ throw new Error("Azure App Services does not have authentication enabled");
3047
+ }
3048
+ if (((_b = env.WEBSITE_AUTH_DEFAULT_PROVIDER) == null ? void 0 : _b.toLowerCase()) !== "azureactivedirectory") {
3049
+ throw new Error("Authentication provider is not Azure Active Directory");
3050
+ }
3051
+ if (((_c = process.env.WEBSITE_AUTH_TOKEN_STORE) == null ? void 0 : _c.toLowerCase()) !== "true") {
3052
+ throw new Error("Token Store is not enabled");
3053
+ }
3054
+ }
3055
+
2937
3056
  const providers = Object.freeze({
2938
3057
  atlassian,
2939
3058
  auth0,
@@ -2951,7 +3070,8 @@ const providers = Object.freeze({
2951
3070
  oidc,
2952
3071
  okta,
2953
3072
  onelogin,
2954
- saml
3073
+ saml,
3074
+ easyAuth
2955
3075
  });
2956
3076
  const defaultAuthProviderFactories = {
2957
3077
  google: google.create(),
@@ -2961,6 +3081,7 @@ const defaultAuthProviderFactories = {
2961
3081
  okta: okta.create(),
2962
3082
  auth0: auth0.create(),
2963
3083
  microsoft: microsoft.create(),
3084
+ easyAuth: easyAuth.create(),
2964
3085
  oauth2: oauth2.create(),
2965
3086
  oidc: oidc.create(),
2966
3087
  onelogin: onelogin.create(),