Closes PLAT-4157
Test Plan:
Attempt to retrieve an access token using a client credentials
grant. The iat of the claimshould be 10 seconds in the future.
Verify you are still able to retrieve an access token.
Verify you cannot retrieve an access token if the iat is more than
30 seconds in the future.
Change-Id: I884f569c3ab4bcafaaa459c70fe3d0c2326153cd
Reviewed-on: https://gerrit.instructure.com/178477
Reviewed-by: Marc Phillips <mphillips@instructure.com>
QA-Review: Marc Phillips <mphillips@instructure.com>
Tested-by: Jenkins
Product-Review: Weston Dransfield <wdransfield@instructure.com>
Closes PLAT-4143
Test Plan:
- Attempt to retrieve an access token using the client
credentials grant type. Make the exp or iat claims
non-numeric
- Verify Canvas responds with a 400 and error message
- Verify the aud must be https
Change-Id: Iefc9b286d9198f0afd759c9a05b1dd8b22647aa4
Reviewed-on: https://gerrit.instructure.com/177837
Tested-by: Jenkins
Reviewed-by: Marc Phillips <mphillips@instructure.com>
QA-Review: Marc Phillips <mphillips@instructure.com>
Product-Review: Weston Dransfield <wdransfield@instructure.com>
Erroneously checking the jti as if it was a nonce.
This allows the tokens to be used more often than
once.
closes PLAT-4084
Test Plan:
Generate a ccg token and attempt to make a call
a few times. Note that it works. Make sure that
you have redis enabled locally.
Change-Id: I4eeed1019ac9ca04956713ed84a2a922b4ffdde0
Reviewed-on: https://gerrit.instructure.com/176586
Reviewed-by: Nathan Mills <nathanm@instructure.com>
QA-Review: Nathan Mills <nathanm@instructure.com>
Tested-by: Jenkins
Product-Review: Marc Phillips <mphillips@instructure.com>
Closes PLAT-4059, PLAT-4060
Test Plan:
- Verify hitting the new endpoint with a valid JWT
results in a 200 response
- Verify a bad request with an error is returned
for the following cases:
* When the aud is not the Canvas iss
* When the JWT params is not a JWT
* When the alg is not RS256
* When the JWT is not signed with the correct
private key
* When the developer key is not found
* When the developer binding is not 'on'
* When the develoepr key is not 'active'
* When the iat is in the future
* When the exp is in the past
* When the nonce has already been used
Change-Id: Ie184fb784212540ad1059b609fa94421c18de31e
Reviewed-on: https://gerrit.instructure.com/174378
Tested-by: Jenkins
Reviewed-by: Marc Phillips <mphillips@instructure.com>
QA-Review: Marc Phillips <mphillips@instructure.com>
Product-Review: Jesse Poulos <jpoulos@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>
closes CNVS-35834
* allow specifying tree, service, and cluster for consul stuff
* check multiple consul keys for each setting (cluster, env, region, global)
test plan:
* an existing consul environment still works
Change-Id: I48e8fadeac2e140973bfc4b41c1cfb386532d15c
Reviewed-on: https://gerrit.instructure.com/125271
Tested-by: Jenkins
Reviewed-by: Rob Orton <rob@instructure.com>
Reviewed-by: Simon Williams <simon@instructure.com>
QA-Review: Tucker McKnight <tmcknight@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
Since some environments share a consul datacenter we need to be able to
differentiate configurations.
Fixes: CNVS-34341
Test Plan:
- Nothing uses this yet but we need to make sure we haven't broken JWT
secrets, the RCE, and Address Book.
Change-Id: I496a8f7d2cafd02c3177a28b348679e552965c0d
Reviewed-on: https://gerrit.instructure.com/99650
Tested-by: Jenkins
Reviewed-by: Simon Williams <simon@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Tyler Pickett <tpickett@instructure.com>
now that services jwts have a concept of workflows and extra data
encoded in the token based on workflow requirements, the existing jwts
endpoint is insufficient for refreshing expired jwts. to some extent
it was already broken since it lost the context when refreshed with
that endpoint
a new refresh endpoint has been addded that takes an exisintg jwt as
a param. this makes it possible to get a new token with the same
workflows, state, and context as an existing expired token as long as
the token matches your user and is requested with a valid session or
oauth token.
tokens may only be used for refresh up to six hours past expiration.
refs CNVS-35199
test plan:
- go to "Pages" in a couse with RCS enabled
- open the console, and get the jwt from ENV.JWT
- wait at least an hour
- make a POST to [same-domain]/api/v1/jwts/refresh with the token as
the `jwt` param
- it should return a json response with a token property
- copy the token
- open up your rails console
- run Canvas::Security.ServicesJwt.new("[copied token]").original_token
- should return hash with the following proerties
- should have :sub with your users global id
- should have :domain that matches your canvas domain
- should have :context_type of Course
- should have :context_id of the course you generated the original
token from
- should have :workflows with rich_content and ui
- repeat process masquerading as another user
- when making a the post to the refresh endpoint use your user and
set a param `as_user_id` to the id of the user you are
masquerading as
- the hash in the console should have
- :sub with the global id of the user you are masquerading as
- :masq_sub with your user id
Change-Id: I399569ed8f2d3d0646728f72910456b77b3ed46a
Reviewed-on: https://gerrit.instructure.com/102909
Reviewed-by: Tucker McKnight <tmcknight@instructure.com>
QA-Review: Tucker McKnight <tmcknight@instructure.com>
Tested-by: Jenkins
Product-Review: Brent Burgoyne <bburgoyne@instructure.com>
refs CNVS-34863
the services jwt thing is just autoloading confusion. by not nesting
the modules, it forces Canvas::Security to load even if you load
Canvas::Security::ServicesJwt first (via an explicit require_dependency
that the spec uses)
Change-Id: Ie08e34ab41502cf8e5c76126d7c6853af9c5947a
Reviewed-on: https://gerrit.instructure.com/103797
Tested-by: Jenkins
Reviewed-by: James Williams <jamesw@instructure.com>
Product-Review: Cody Cutrer <cody@instructure.com>
QA-Review: Cody Cutrer <cody@instructure.com>
for a given workflow, services consuming canvas jwts may need access
to additional state (feature flags, permissions, etc). this commit
introduces the ability to to define state requirements for a jwt
based on its workflows, context and user.
the concept of jwt workflow has been made plural and it expects it to
be an array of workflows. a token for one service may need to be used
in multiple workflows (i.e. a quiz token may need to work as a rich
content token as well).
this commit defines the :rich_content workflow which includes upload
and usage rights information.
tokens also include context type and id. since the workflow state may
be specific to the context, this provides a way for the service to
validate that the token is being used in the correct context.
code that generates conditional-release tokens has been updated to use
the workflows array. this won't break anything becuase, even though it
is including in the token, it is not being validated yet. future
validations will check for inclusion in the array.
refs CNVS-30966, refs CNVS-32094
test plan:
- launch a page with the rich content service side bar
- ensure the request to the proxy don't return 401 status codes
- a test plan for the consuption of the new data in the token will
come with a seperate RCS commit
Change-Id: I9e643995cb98547664f721a9b5d8c9441010eea9
Reviewed-on: https://gerrit.instructure.com/89012
Reviewed-by: Simon Williams <simon@instructure.com>
Tested-by: Jenkins
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Brent Burgoyne <bburgoyne@instructure.com>
- callback jwt for canvas
- assignment info
refs: CYOE-74
Test plan:
1. Launch conditional release endpoint
2. Ensure CONDITIONAL_RELEASE_JWT are in the JS env
for assignments, quizzes, and discussions
3. Decode jwt using canvas keys
4. Verify that add'l data is present
Change-Id: Ib33d15ea6fc91fc3c10e81c74ef52dc122687e1c
Reviewed-on: https://gerrit.instructure.com/77476
Reviewed-by: Dan Minkevitch <dan@instructure.com>
Product-Review: Dan Minkevitch <dan@instructure.com>
Reviewed-by: Christian Prescott <cprescott@instructure.com>
Tested-by: Jenkins
QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com>
refs: CYOE-75
Test plan:
1. Ensure that consul.yml is present in your config and that
it contains keys for canvas:signing-secret and
canvas:encryption-secret.
2. Load the conditional release settings page from course
settings (http://canvas.docker/courses/1/score_range_defaults)
3. View source of the page
4. Verify that ENV["CONDITIONAL_RELEASE_JWT"] is added in the
ENV array at the bottom of the source file.
5. Verify the contents of the JWT
`ECOSYSTEM_SECRET=<signing-secret> ECOSYSTEM_KEY=<encryption-key>
bin/decode_jwt <jwt>`
(Before g/74981, you can manually base-64 decode:
`echo <jwt> | base64 --decode | ECOSYSTEM_SECRET=<>
ECOSYSTEM_KEY=<> bin/decode_jwt`
Change-Id: Iec8c24d6b5d6e3e855c7c515295485a52012b9f1
Reviewed-on: https://gerrit.instructure.com/75109
Tested-by: Jenkins
Reviewed-by: Christian Prescott <cprescott@instructure.com>
QA-Review: Jahnavi Yetukuri <jyetukuri@instructure.com>
Product-Review: Dan Minkevitch <dan@instructure.com>
fixes CNVS-28330
TEST PLAN:
1) generate a JWT with the "for_user" method
2) if a masquerading user is provided, it should be included in the
body
3) eventually, using a wrapping service should be able to preserve
audit trail across an external api call with JWT
Change-Id: Ic10bcc4ac2e8b4222005d765cec2df3dd4740f64
Reviewed-on: https://gerrit.instructure.com/75741
Tested-by: Jenkins
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Ethan Vizitei <evizitei@instructure.com>
closes CNVS-27597
We need to not slam consul for rarely changing data.
the '#find' method still gets the value from consul everytime.
Cache can be infinite or with timeout.
TEST PLAN:
1) have some data in consul for what the signing secret is for canvas
2) Make sure to query it (Canvas::Security::ServicesJwt.signing_secret)
3) change the consul data
4) query it again, it should not have updated
5) send a SIGHUP
6) query it again, it should have changed
Change-Id: I5b923b8e44ab90692e87969c494a7c65fafcad72
Reviewed-on: https://gerrit.instructure.com/73198
Reviewed-by: Cody Cutrer <cody@instructure.com>
Reviewed-by: Brian Palmer <brianp@instructure.com>
Tested-by: Jenkins
Reviewed-by: David Adams <dadams@instructure.com>
QA-Review: Jeremy Putnam <jeremyp@instructure.com>
Product-Review: Simon Williams <simon@instructure.com>
refs CNVS-24823
having the host in the token means we don't need to pass multiple
parameters to give a service context for proxying API calls.
TEST PLAN:
1) jwt should still be able to be generated
2) decypted/decoded JWT should include a 'domain' entry
Change-Id: Ib886e37a12aba23f4f938a4b5cfa10adb44083af
Reviewed-on: https://gerrit.instructure.com/71727
Tested-by: Jenkins
Reviewed-by: Simon Williams <simon@instructure.com>
Product-Review: Ethan Vizitei <evizitei@instructure.com>
QA-Review: Ethan Vizitei <evizitei@instructure.com>
closes CNVS-26734
distributing env vars through production is harder
than updating a shared highly available store. We put this stuff
in consul now so it's easy to update everywhere at once.
also clean up webmock spec usage, it causes a lot of errors
because it's configuration seeps outside the specs it's currently used
in
TEST PLAN:
1) no production changes (does not touch app code)
2) clean install, clean config directory
3) copy docker-compose/config/ files to your config directory
4) you shouldn't be missing any config files when you start your
compose file up
5) Canvas::DynamicSettings.find("canvas") should give you a hash
with your secrets from the init values in your config file
6) ServicesJwt.signing_secret and ServicesJwt.encryption secret
should pull those same values
7) if you have env vars for ECOSYSTEM_KEY or ECOSYSTEM_SECRET, they
should be ignored
Change-Id: I3b3c1b19d6e2a05af3e6caa2e0af6c5d1dc6df66
Reviewed-on: https://gerrit.instructure.com/71559
Tested-by: Jenkins
Reviewed-by: Simon Williams <simon@instructure.com>
Product-Review: Ethan Vizitei <evizitei@instructure.com>
QA-Review: Ethan Vizitei <evizitei@instructure.com>
fixes CNVS-24777
Also refactor the interface between the
canvas security module (which is getting fat)
and the ServicesJwt class (which was anemic).
TEST PLAN:
1) no behavior change
2) if you decrypt/decode a token, the JTI
should look like a secure-random gen'd string
(e.g. a8568287-eb98-4b58-b715-feb6bd02fb1f)
Change-Id: I90d4f0b343f1170303a86749e6253cc740a220a2
Reviewed-on: https://gerrit.instructure.com/66483
Tested-by: Jenkins
Reviewed-by: Simon Williams <simon@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Product-Review: Ethan Vizitei <evizitei@instructure.com>
closes CNVS-24286
Add JWT (wrapped and signed by shared secret)
as a viable authentication method.
Also remove deprecation errors from login template
TEST PLAN:
1) have ECOSYSTEM_* env vars set (docker helps)
2) login as a user
3) take a token from "/jwts/generate"
4) wrap that token in another token signed
with the shared secret (ECOSYSTEM_SECRET,
see services_jwt_spec.rb for a way to do this)
5) use the base64 encoded string as a bearer
token for canvas
6) try it again in 70 minutes or so (the same
token), it should now be expired.
Change-Id: I721f42d7c9ca7edc82bc75b116354dd3edc50a88
Reviewed-on: https://gerrit.instructure.com/66110
Reviewed-by: Cody Cutrer <cody@instructure.com>
Tested-by: Jenkins
QA-Review: August Thornton <august@instructure.com>
Product-Review: Ethan Vizitei <evizitei@instructure.com>