From 112dac9803764357c8deaa9569f390976499ac4e Mon Sep 17 00:00:00 2001 From: Justin Ball Date: Tue, 25 Oct 2022 15:03:59 -0600 Subject: [PATCH] Backported changes --- app/assets/builds/.keep | 0 app/controllers/application_controller.rb | 24 +++++++++++++++++++++++ app/controllers/concerns/lti_support.rb | 2 ++ app/lib/lti_advantage/exceptions.rb | 3 +++ app/lib/lti_advantage/params.rb | 4 ++++ client/apps/hello_world/app.jsx | 7 ++----- db/seeds.rb | 21 +++++++++++++++++--- package.json | 5 +++-- yarn.lock | 9 ++++++++- 9 files changed, 64 insertions(+), 11 deletions(-) delete mode 100644 app/assets/builds/.keep diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 04bf72056..e5f8447b0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -124,6 +124,24 @@ def handle_no_deployment render "lti_deployments/index", layout: "application" end + rescue_from JWT::DecodeError, with: :handle_invalid_jwt + def handle_invalid_jwt(exception) + json_options = { + exception: exception, + backtrace: exception.backtrace, + } + render_error 401, "Invalid JWT: #{exception.message}", json_options + end + + rescue_from LtiAdvantage::Exceptions::InvalidLTIVersion, with: :handle_invalid_lti_launch + def handle_invalid_lti_launch(exception) + json_options = { + exception: exception, + backtrace: exception.backtrace, + } + render_error 500, "Invalid LTI Launch: #{exception.message}", json_options + end + def set_rollbar_scope if !current_application_instance&.rollbar_enabled? Rollbar.configure { |config| config.enabled = false } @@ -207,6 +225,12 @@ def set_lti_advantage_launch_values params[:id_token], ) @lti_params = LtiAdvantage::Params.new(@lti_token) + + # Validate LTI version + if @lti_params.version != "1.3" + raise LtiAdvantage::Exceptions::InvalidLTIVersion, "Invalid LTI version #{@lti_params.version}" + end + @lti_launch_config = JSON.parse(params[:lti_launch_config]) if params[:lti_launch_config] @is_deep_link = true if LtiAdvantage::Definitions.deep_link_launch?(@lti_token) @app_name = current_application_instance.application.client_application_name diff --git a/app/controllers/concerns/lti_support.rb b/app/controllers/concerns/lti_support.rb index b2a416a17..ee3d7bf22 100644 --- a/app/controllers/concerns/lti_support.rb +++ b/app/controllers/concerns/lti_support.rb @@ -14,6 +14,8 @@ def do_lti # Validate the state by checking the database for the nonce return user_not_authorized if !LtiAdvantage::OpenId.validate_open_id_state(params["state"]) + # Validate the LTI version + set_lti_advantage_launch_values user = LtiAdvantage::LtiUser.new(@lti_token, current_application_instance).user sign_in(user, event: :authentication, store: false) diff --git a/app/lib/lti_advantage/exceptions.rb b/app/lib/lti_advantage/exceptions.rb index 41d7979fa..60d6d2820 100644 --- a/app/lib/lti_advantage/exceptions.rb +++ b/app/lib/lti_advantage/exceptions.rb @@ -15,6 +15,9 @@ class ScoreError < StandardError class NoLTIDeployment < StandardError end + class InvalidLTIVersion < StandardError + end + class InvalidIssuer < StandardError end diff --git a/app/lib/lti_advantage/params.rb b/app/lib/lti_advantage/params.rb index 107f43bd6..82e8232c4 100644 --- a/app/lib/lti_advantage/params.rb +++ b/app/lib/lti_advantage/params.rb @@ -61,6 +61,10 @@ def course_name end end + def version + token[LtiAdvantage::Definitions::LTI_VERSION] + end + # This extracts the custom parameters from the jwt token from the lti launch # These values must be added to the developer key under "Custom Fields" # for example: canvas_course_id=$Canvas.course.id diff --git a/client/apps/hello_world/app.jsx b/client/apps/hello_world/app.jsx index e09845b0a..2a746df69 100644 --- a/client/apps/hello_world/app.jsx +++ b/client/apps/hello_world/app.jsx @@ -1,6 +1,4 @@ -import 'core-js'; -import 'regenerator-runtime/runtime'; -import es6Promise from 'es6-promise'; + import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; @@ -14,8 +12,7 @@ import initResizeHandler from '../../common/libs/resize_iframe'; import './styles/styles.scss'; -// Polyfill es6 promises for IE -es6Promise.polyfill(); + class Root extends React.PureComponent { static propTypes = { diff --git a/db/seeds.rb b/db/seeds.rb index 4a0a58c61..b473e4088 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,6 +1,3 @@ -admin = CreateAdminService.new.call -puts "CREATED ADMIN USER: " << admin.email - secrets = Rails.application.secrets # Add sites @@ -19,6 +16,9 @@ { url: "https://blackboard.com", }, + { + url: "https://ltiadvantagevalidator.imsglobal.org", + }, ] # Each API endpoint must include a list of LTI and internal roles that are allowed to call the endpoint. @@ -188,6 +188,14 @@ token_url: "https://lti-ri.imsglobal.org/platforms/275/access_tokens", oidc_url: "https://lti-ri.imsglobal.org/platforms/275/authorizations/new", }, + { + # IMS Global Validator application + iss: "https://ltiadvantagevalidator.imsglobal.org", + client_id: "imstester_7ec088e", + jwks_url: "https://oauth2server.imsglobal.org/jwks", + token_url: "https://ltiadvantagevalidator.imsglobal.org/ltitool/authcodejwt.html", + oidc_url: "https://ltiadvantagevalidator.imsglobal.org/ltitool/oidcauthurl.html", + }, { # Blackboard iss: "https://blackboard.com", @@ -312,6 +320,13 @@ def setup_application_instances(application, application_instances) setup_application_instances(application, application_instances) end + # Add the admin user to the admin instance + admin_inst = ApplicationInstance.find_by(lti_key: Application::ADMIN) + Apartment::Tenant.switch(admin_inst.tenant) do + admin = CreateAdminService.new.call + puts "CREATED ADMIN USER: " << admin.email + end + bundles.each do |attrs| current_bundle = Bundle.find_or_create_by(key: attrs[:key]) current_bundle.update!(name: attrs[:name], shared_tenant: attrs[:shared_tenant] == true) diff --git a/package.json b/package.json index 71e4428f7..e91309540 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "lint_fix": "eslint client --fix", "nuke": "rm -rf node_modules", "inspect_fuel": "\"${EDITOR:-vi}\" ./node_modules/atomic-fuel", - "build": "yarn run build_packs", + "build": "cross-env NODE_ENV=production yarn run build_packs", "hot": "node esbuild.js dev client/packs/*.*", - "build_packs": "node esbuild.js prod client/packs/*.*" + "build_packs": "cross-env NODE_ENV=production node esbuild.js prod client/packs/*.*" }, "repository": { "type": "git", @@ -106,6 +106,7 @@ "devDependencies": { "@babel/eslint-parser": "^7.17.0", "babel-jest": "^28.1.0", + "cross-env": "^7.0.3", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", "enzyme-to-json": "^3.6.2", diff --git a/yarn.lock b/yarn.lock index 8618a2140..14d374622 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2643,7 +2643,14 @@ create-react-class@^15.5.1: loose-envify "^1.3.1" object-assign "^4.1.1" -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==