Commit 76e82cb4 authored by Grant's avatar Grant
Browse files

Merge branch 'dependabot-npm_and_yarn-packages-server-openid-client-6.1.7' into 'main'

Bump openid-client from 5.7.1 to 6.1.7 in /packages/server

See merge request sc07/canvas!41
parents def9c685 86d7e1ee
Loading
Loading
Loading
Loading
+17 −38
Original line number Diff line number Diff line
@@ -12340,9 +12340,9 @@
      }
    },
    "node_modules/jose": {
      "version": "4.15.9",
      "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz",
      "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==",
      "version": "5.9.6",
      "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz",
      "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==",
      "funding": {
        "url": "https://github.com/sponsors/panva"
      }
@@ -12574,17 +12574,6 @@
        "loose-envify": "cli.js"
      }
    },
    "node_modules/lru-cache": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
      "dependencies": {
        "yallist": "^4.0.0"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/magic-string": {
      "version": "0.30.8",
      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
@@ -12916,6 +12905,14 @@
        "node": ">=0.10.0"
      }
    },
    "node_modules/oauth4webapi": {
      "version": "3.1.4",
      "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.1.4.tgz",
      "integrity": "sha512-eVfN3nZNbok2s/ROifO0UAc5G8nRoLSbrcKJ09OqmucgnhXEfdIQOR4gq1eJH1rN3gV7rNw62bDEgftsgFtBEg==",
      "funding": {
        "url": "https://github.com/sponsors/panva"
      }
    },
    "node_modules/object-assign": {
      "version": "4.1.1",
      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -13036,14 +13033,6 @@
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/oidc-token-hash": {
      "version": "5.0.3",
      "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz",
      "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==",
      "engines": {
        "node": "^10.13.0 || >=12.0.0"
      }
    },
    "node_modules/on-finished": {
      "version": "2.4.1",
      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -13081,27 +13070,17 @@
      }
    },
    "node_modules/openid-client": {
      "version": "5.7.1",
      "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz",
      "integrity": "sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==",
      "version": "6.1.7",
      "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.1.7.tgz",
      "integrity": "sha512-JfY/KvQgOutmG2P+oVNKInE7zIh+im1MQOaO7g5CtNnTWMociA563WweiEMKfR9ry9XG3K2HGvj9wEqhCQkPMg==",
      "dependencies": {
        "jose": "^4.15.9",
        "lru-cache": "^6.0.0",
        "object-hash": "^2.2.0",
        "oidc-token-hash": "^5.0.3"
        "jose": "^5.9.6",
        "oauth4webapi": "^3.1.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/panva"
      }
    },
    "node_modules/openid-client/node_modules/object-hash": {
      "version": "2.2.0",
      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/optionator": {
      "version": "0.9.3",
      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -16664,7 +16643,7 @@
        "express": "^4.21.2",
        "express-rate-limit": "^7.5.0",
        "express-session": "^1.18.1",
        "openid-client": "^5.7.1",
        "openid-client": "^6.1.7",
        "prom-client": "^15.1.3",
        "rate-limit-redis": "^4.2.0",
        "redis": "^4.7.0",
+0 −46
Original line number Diff line number Diff line
@@ -35,11 +35,6 @@ export const AuthErrors = () => {

  return (
    <>
      <RPError
        isOpen={params.get(Params.TYPE) === "rp"}
        onClose={onClose}
        params={params}
      />
      <OPError
        isOpen={params.get(Params.TYPE) === "op"}
        onClose={onClose}
@@ -86,47 +81,6 @@ const BannedError = ({
  );
};

/**
 * This is for RP errors, which can be triggered by modifying data sent in callbacks
 *
 * These errors can typically be retried
 *
 * @param param0
 * @returns
 */
const RPError = ({
  isOpen,
  onClose,
  params,
}: {
  isOpen: boolean;
  onClose: () => void;
  params: URLSearchParams;
}) => {
  return (
    <Modal isOpen={isOpen} onClose={onClose} isDismissable={false}>
      <ModalContent>
        {(onClose) => (
          <>
            <ModalHeader>Login Error</ModalHeader>
            <ModalBody>
              <b>Error:</b> {params.get(Params.ERROR)}
              <br />
              <br />
              <b>Error Description:</b> {params.get(Params.ERROR_DESC)}
            </ModalBody>
            <ModalFooter>
              <Button color="primary" href="/api/login" as={Link}>
                Login
              </Button>
            </ModalFooter>
          </>
        )}
      </ModalContent>
    </Modal>
  );
};

/**
 * This is for OP errors, these might not be retryable
 * @param param0
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@
    "express": "^4.21.2",
    "express-rate-limit": "^7.5.0",
    "express-session": "^1.18.1",
    "openid-client": "^5.7.1",
    "openid-client": "^6.1.7",
    "prom-client": "^15.1.3",
    "rate-limit-redis": "^4.2.0",
    "redis": "^4.7.0",
+9 −39
Original line number Diff line number Diff line
import { Router } from "express";
import { prisma } from "../lib/prisma";
import { OpenID } from "../lib/oidc";
import { TokenSet, errors as OIDC_Errors } from "openid-client";
import { ResponseBodyError } from "openid-client";
import { getLogger } from "../lib/Logger";
import Canvas from "../lib/Canvas";
import { RateLimiter } from "../lib/RateLimiter";
@@ -44,12 +44,7 @@ app.get("/login", (req, res) => {
    return;
  }

  res.redirect(
    OpenID.client.authorizationUrl({
      prompt: "consent",
      scope: "openid instance",
    })
  );
  res.redirect(OpenID.getAuthorizationURL());
});

app.get("/logout", (req, res) => {
@@ -78,34 +73,19 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
    return;
  }

  let exchange: TokenSet;
  let exchange: Awaited<ReturnType<typeof OpenID.exchangeToken>>;

  try {
    const params = OpenID.client.callbackParams(req);
    exchange = await OpenID.client.callback(OpenID.getRedirectUrl(), params);
    exchange = await OpenID.exchangeToken(req.originalUrl);
  } catch (e) {
    if (e instanceof OIDC_Errors.RPError) {
      // client error

      res.redirect(
        "/" +
          buildQuery({
            TYPE: "rp",
            ERROR: e.name,
            ERROR_DESC: e.message,
          })
      );
      return;
    }

    if (e instanceof OIDC_Errors.OPError) {
      // server error
    console.error(e);

    if (e instanceof ResponseBodyError) {
      switch (e.error) {
        case "invalid_client":
          // this happens when we're configured with invalid credentials
          Logger.error(
            "OpenID is improperly configured. Cannot exchange tokens, do I have valid credetials?"
            "OpenID is improperly configured. Cannot exchange tokens, do I have valid credentials?"
          );
          res.redirect(
            "/" +
@@ -127,16 +107,6 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
          );
          return;
      }

      res.redirect(
        "/" +
          buildQuery({
            TYPE: "op",
            ERROR: e.error,
            ERROR_DESC: e.error_description,
          })
      );
      return;
    }

    res.redirect(
@@ -158,7 +128,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
  }

  try {
    const whoami = await OpenID.client.userinfo<{
    const whoami = await OpenID.userInfo<{
      instance: {
        software: {
          name: string;
@@ -173,7 +143,7 @@ app.get("/callback", RateLimiter.HIGH, async (req, res) => {
          name?: string;
        };
      };
    }>(exchange.access_token);
    }>(exchange.access_token, exchange.claims()!.sub);

    const [username, hostname] = whoami.sub.split("@");

+27 −8
Original line number Diff line number Diff line
import { BaseClient, Issuer } from "openid-client";
import * as openid from "openid-client";

class OpenID_ {
  issuer: Issuer<BaseClient> = {} as any;
  client: BaseClient = {} as any;
  config: openid.Configuration = {} as any;

  async setup() {
    if (process.env.INHIBIT_LOGIN) {
@@ -14,18 +13,38 @@ class OpenID_ {

    const { AUTH_ENDPOINT, AUTH_CLIENT, AUTH_SECRET } = process.env;

    this.issuer = await Issuer.discover(AUTH_ENDPOINT);
    this.client = new this.issuer.Client({
      client_id: AUTH_CLIENT,
    this.config = await openid.discovery(new URL(AUTH_ENDPOINT), AUTH_CLIENT, {
      client_secret: AUTH_SECRET,
      response_types: ["code"],
      redirect_uris: [this.getRedirectUrl()],
    });
  }

  getRedirectUrl() {
    return process.env.OIDC_CALLBACK_HOST + "/api/callback";
  }

  getAuthorizationURL() {
    return openid
      .buildAuthorizationUrl(this.config, {
        redirect_uri: this.getRedirectUrl(),
        prompt: "consent",
        scope: "openid instance",
      })
      .toString();
  }

  exchangeToken(relativePath: string) {
    return openid.authorizationCodeGrant(
      this.config,
      new URL(relativePath, process.env.OIDC_CALLBACK_HOST)
    );
  }

  userInfo<Data extends {} = {}>(
    accessToken: string,
    expectedSub: string
  ): Promise<openid.UserInfoResponse & Data> {
    return openid.fetchUserInfo(this.config, accessToken, expectedSub) as any;
  }
}

export const OpenID = new OpenID_();