- Remove `Lti::Ims::NamesAndRolesController`'s inclusion of
`Lti::Ims::AccessTokenHelper` in favor of a recently
introduced concern: `Lti::Ims::Concerns::AdvantageServices`. This
includes a reimplementation of `Lti::Oauth2::AccessToken` as
`Lti::Ims::Concerns::AdvantageServices::AccessToken`, which has
many of the same capabilities, but none of the LTI 2 baggage.
- Most low-level JWT validation is delegated to `Canvas::Security`
and `Canvas::Security::JwtValidator`. The former provides symmetry
with `Canvas::Oauth::ClientCredentialsProvider` eso w/r/t using
Canvas encryption keys as signing keys. The latter also aligns well
with that same provider, though its `jti` handling may need to
be relaxed in the future.
- ***This commit intentionally avoids extensive modifications to
`Lti::Ims::Concerns::GradebookServices` and related controllers. The
expectation is that `GradebookServices` should just include
`AdvantageServices` and could thus eliminate many of its methods.
But this has been deferred, partly to keep commit size down and
partly to avoid unilateral contract changes to dependent controllers.
- Most of this commit, then, is really just suffling tests around
from `names_and_roles_controller_spec.rb` into
`advantage_services_shared_examples.rb` so other LTI Advantage
controllers can integrate the same validations.
`advantage_services_shared_context.rb` expresses the data setup
needs of `advantage_services_shared_examples.rb`, along with a few
helper methods.
- Eliminates custom tool/account chain walking in
`NamesAndRolesController` in favor of
`ContextExternalTool#all_tools_for`. Latter's use is in
`AdvantageServices`, so should be readily reusable from other
LTI Advantage controllers.
Closes LTIA-28
Test Plan
* This is largely a technical refactoring so testing should focus
primarily on regression checks against NRPS v2 callbacks, especially
to ensure they still require valid access tokens issues via
client credentials.
* Functional differences are limited to newly added validation of
JWT claims embedded in those access tokens. These are difficult to
test since Canvas is responsible for generating the tokens. So
either Canvas code needs to be temporarily modified to generate
variously incorrect access tokens, or an out of band tool needs to
be implemented to generate such tokens. Claims to be validated:
1. `sub` - must be an active developer key's global ID, e.g.
"10000000000020"
2. `aud` - must be the OAuth2 access token issuance URL, i.e.
`<host>/login/oauth2/token`
3. `iat` - must be in the past
4. `exp` - must be in the future
5. `jti` - must be present
6. `scopes` - must include
https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly
7. <signature> - Must use `HS256` algorithm and use the Canvas
encryption key as the signing secret.
Change-Id: I14b431e11180f06e9edd4f5dfd3b04ed931ea73e
Reviewed-on: https://gerrit.instructure.com/167361
Tested-by: Jenkins
QA-Review: Samuel Barney <sbarney@instructure.com>
Reviewed-by: Marc Phillips <mphillips@instructure.com>
Product-Review: Karl Lloyd <karl@instructure.com>
- NRPS v2 invocations referencing a `Course` Context now attempt to
resolve a `ContextExternalTool` (CET) given the JWT `AccessToken`
attached to the request. In order to return memberships, that CET
must be active and must either be bound directly to the `Course` or
to an `Account` in the `Course`'s' `Account` chain.
- `AccessToken` must be associated with an active `DeveloperKey`
(DK), and the search for the "operative" CET for the current request
is executed against that DK's list of active CETs.
- `Course`-level CETs are preferred, followed by `Account`-level
CETs.
- LTI 1.3/Advantage features must be turned on at the CET and root
`Account` levels.
- The `AccessToken`'s'JWT signature and security claims are not
themselves validated... that comes later.
- `Group` Context support also comes later.
Closes LTIA-26
Test Plan:
- Via Rails console create a `DeveloperKey` associated with the
public key of a Tool configured in the IMS LTI 1.3/Advantage
Reference Implementation (RI) and the root `Account` in your env
- Via Rails console, create a LTI 1.3-enabled
`ContextExternalTool` with a `course_navigation` placement and
linked to the just-created `DeveloperKey` and its `Account`
- For a `Course` owned by this `Account`, verify that direct
invocations of the NRPS v2 API.
(`GET /api/lti/courses/:course_id/names_and_roles`) fail with
a 401 and a message complaining about a missing access token.
- Navigate to the `Course` and click the newly created nav link,
which should successfully launch the RI.
- Click the 'Request Names and Roles' link in the RI. Verify
course is reported in the NRPS v2 format.
- Deactivate the `DeveloperKey`. Click 'Request Names and Roles'
link in the RI. Verify a (non-descript) on-screen error message.
- Re-enable the `DeveloperKey` and re-verify the same behavior
for a `Course` associated with a sub-`Account`.
- Delete the CET, verify that NRPS v2 invocations from the RI
fail.
- Via Rails console, create a new CET linked to the same
`DeveloperKey`, but now attached to the sub-`Account` `Course`.
- Re-verify NRPS v2 invocation from the RI.
- *Consult JIRA for full acceptance criteria.
Change-Id: Ie9625ea8d6ce5e6f59e3c7ce1d10d0a47291afa4
Reviewed-on: https://gerrit.instructure.com/167183
Tested-by: Jenkins
QA-Review: Samuel Barney <sbarney@instructure.com>
Reviewed-by: Marc Phillips <mphillips@instructure.com>
Product-Review: Karl Lloyd <karl@instructure.com>
Oauth2.0 client_credentials grant_type is added as a means
to support LTI Advantage services. Will accept only the
client_assertion_type of jwt-bearer and returns a JWS as
the access token. LTI services using the jws will be able to
authenticate, but other api endpoints will fail when using
this jwt.
closes PLAT-3659
Test Plan:
- Create an oauth 2.0 request using a jwt signed by a
developer key
- Request should be validated and returns a jwt with
the correct scopes
Change-Id: I786b71e39f8d3c2c9c71aa3eff4ea490f6d56285
Reviewed-on: https://gerrit.instructure.com/161245
Tested-by: Jenkins
QA-Review: Weston Dransfield <wdransfield@instructure.com>
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Product-Review: Marc Alan Phillips <mphillips@instructure.com>
Some production installations have a beta or test environment that is
refreshed with data from production, and is used as a place to test
integrations or new features. In that case, you may want to create
a developer key that only works against this test instance, which has
traditionally meant making the following tradeoff:
- Create the key in the test instance directly, which means it will be
removed the next time the data is refreshed
- Create the key in production, which means the key works against the
production instance as well
This new functionality allows the best of both worlds: create the key in
production for persistance, but only allow it to function against a test
cluster.
To enable test cluster functionality, you need a plugin that overrides
`ApplicationController.test_cluster?` to return appropriately for the
environment.
To see the functionality, you need to set:
`Setting.set("dev_key_test_cluster_checks_enabled", true)`
closes PLAT-3392
[ci no-db-snapshot]
test plan:
- First ensure that all existing developer key functionality works and
no new functionality appears without any action taken
- Then set Setting.set("dev_key_test_cluster_checks_enabled", true), you
should see the new option available in the new dev key UI
- Create a key with and without the new option checked. Access tokens
from the key without it check should still work normally. Tokens from
the key with it checked should not work
- Now manually override `ApplicationController.test_cluster?` to be
true.
- Tokens from both keys should now work
Change-Id: I5bbb46782d19c26a7b703834aaa507b0cb10039a
Reviewed-on: https://gerrit.instructure.com/153035
Reviewed-by: Cody Cutrer <cody@instructure.com>
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Tested-by: Jenkins
QA-Review: August Thornton <august@instructure.com>
Product-Review: Karl Lloyd <karl@instructure.com>
refs PLAT-2649
test plan:
you can do an LTI2 JWT launch for a tool that suports the
correct security profile
Change-Id: I31a06243a171aaabe28552b7ee3866e807a86c30
Reviewed-on: https://gerrit.instructure.com/113018
Tested-by: Jenkins
Reviewed-by: Andrew Butterfield <abutterfield@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
fixes PLAT-2633
Test plan:
* Install an LTI 2 in a course
* Export that course
* Ensure that the registration url is persisted in the imscc file
Change-Id: Ifc3b1ab9b7aeed3985bcddc7ae709e69215eb051
Reviewed-on: https://gerrit.instructure.com/117314
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Tested-by: Jenkins
Reviewed-by: Nathan Mills <nathanm@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Andrew Butterfield <abutterfield@instructure.com>
Closes PLAT-2680
Test Plan:
- As a student submit to an assignment associted with an
LTI 2 tool.
- Using the LTI 2 submission service retrieve the submission
- Request the submission attachment using the value of
the `url` string provided in the submission JSON payload (
This will require retrieveing and using a JWT access token).
- Veriy that the attachment is downloaded.
- From a different shard attempt to use the same URL to download
the attachment.
- Verify the attachment is downloaded.
Change-Id: Ia60cd3dfccdea835ead109ba4b7d6fa2147b3a71
Reviewed-on: https://gerrit.instructure.com/116093
Tested-by: Jenkins
Reviewed-by: Nathan Mills <nathanm@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Weston Dransfield <wdransfield@instructure.com>
fixes PLAT-2422
test plan:
- use the oauth2 flow to register a tool proxy using just
the reg_key and reg_password
-it should work
-the developer credentials should still work
-the legacy oauth1 should still work
Change-Id: I74f754c06f0d4a46158588f39bee75321fad3a3d
Reviewed-on: https://gerrit.instructure.com/106623
Tested-by: Jenkins
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
fixes PLAT-2354
test plan:
-create a submission with an attachment on an assignment that has
the originality detection tool associated
-hit the lti2 endpoint to get the submission json
-from the submission json get the attachment url
-use the lti2 credentials with the attachment url to download
the attachment
-it should download the attachment
-try the following, they should all return 401:
-try to download the attachment without the lti2 credentials
-try to download the attachment using a canvas session
-try to monkey with the url to download a different attachment you
shouldn't have access to, i.e. on a different assignment
Change-Id: Ib38bbdbe9a1a649826a6bc98dd0d19b71a32635e
Reviewed-on: https://gerrit.instructure.com/104989
Tested-by: Jenkins
Reviewed-by: Michael Brewer-Davis <mbd@instructure.com>
Reviewed-by: Andrew Butterfield <abutterfield@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
fixes PLAT-2323
test plan:
-attempt to register a TP using the authorization code workflow
-it should let you create a tool proxy
-attempt to register a TP using the client credentials JWT workflow
-it should give you a 401
-attempt to register using a custom Tool Consumer Profile
-it should let you
there is a problem with using developer keys to register tools
since we aren't using a onetime token it no longer requires a admin
to kick off the process to install the tool. We will need to do
something to address this, and ensure they have permission to install
in this context
Change-Id: I95ed14a8f818f02dab8340dfde3cc6327c06c793
Reviewed-on: https://gerrit.instructure.com/103267
QA-Review: August Thornton <august@instructure.com>
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Reviewed-by: Andrew Butterfield <abutterfield@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
Tested-by: Jenkins
Fixes PLAT-2226
Test Plan:
- Attempt to retrieve a AuthorizationJWT following the
documentation in authorization_controller. Use a valid
Canvas dev key global id as the 'sub' claim.
- Verify an AuthorizationJWT is returned
- Verify the 'sub' claim of the AuthorizationJWT
is set to the canvas developer key used in the
original request
- Register an LTI2 tool, but do the following in the
tool proxy create post request:
* Do not send any OAuth headers (even reg_key/password)
* Send the AuthorizationJWT as an authorization header like this:
Authorization Bearer <AuthorizationJWT>
- Verify the tool proxy is regeistered.
- Verify registering a tool with reg_key/password still works
Change-Id: I4266c672ad0cda7b2300de882c856c32b31be61e
Reviewed-on: https://gerrit.instructure.com/101783
Reviewed-by: Nathan Mills <nathanm@instructure.com>
Tested-by: Jenkins
QA-Review: August Thornton <august@instructure.com>
Product-Review: Weston Dransfield <wdransfield@instructure.com>
fixes PLAT-2209
test plan:
you don't need the iss or kid claims anymore to get an
LTI2 access token
Change-Id: I12964994d089ee599adcdb035a6bf07dd644b696
Reviewed-on: https://gerrit.instructure.com/101432
Tested-by: Jenkins
QA-Review: August Thornton <august@instructure.com>
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
fixes: PLAT-2127
test plan:
- Hit the LTI2 Auth Token endpoint to get an AccessToken
- The access token should be a canvas signed JWT
Change-Id: If09dfc658ecc40fc525b9c49d49110539573e657
Reviewed-on: https://gerrit.instructure.com/99946
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Tested-by: Jenkins
QA-Review: August Thornton <august@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>
fixes PLAT-1966
test plan:
create JWT folowing the documentation
you should get an access token
Change-Id: I5e159fb4fd4e40174a3f8712013cd43b3582ee0e
Reviewed-on: https://gerrit.instructure.com/99608
QA-Review: August Thornton <august@instructure.com>
Tested-by: Jenkins
Reviewed-by: Weston Dransfield <wdransfield@instructure.com>
Product-Review: Nathan Mills <nathanm@instructure.com>