canvas-lms/lib/file_authenticator.rb

97 lines
3.4 KiB
Ruby
Raw Normal View History

#
# Copyright (C) 2018 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
class FileAuthenticator
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
attr_reader :user, :acting_as, :access_token, :root_account, :oauth_host
fix inst-fs on redirect through files domain fixes RECNVS-462 in a production-like environment, the redirect to inst-fs happens after a redirect to the files domain. on the files domain, the user's session is not preserved and @current_user and logged_in_user are not set. but in their place a value indicating the user is placed in the session. when that value is present and the current user is absent, inst-fs should use the session value in generating JWTs. note: currently the session value only indicates the @current_user and any information about the logged_in_user, if different, is lost when arriving at the files domain. this will be fixed in a separate commit; until it is, inst-fs will not work with a files domain while masquerading. test-plan: - have a canvas environment with a files domain and inst-fs enabled - upload an image to a course - open the network tab in the developer tools then preview the image - there should be a `preview` request to the current domain, which redirects to the files domain - there should be the request to the files domain, which redirects to inst-fs - there should be the request to inst-fs that returns with a 200 and the image (i.e. the preview works) - the JWT in the inst-fs request should include the correct user_id claim when decoded Change-Id: Ic804b52e24739a06355df5584d3f189ae8340366 Reviewed-on: https://gerrit.instructure.com/151070 Tested-by: Jenkins Reviewed-by: Michael Jasper <mjasper@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-23 03:32:58 +08:00
# implements the minimum interface necessary for the temporary API client
# work around when given just a developer key. we'll need real access tokens
# for the long term solution
class FakeAccessToken
attr_reader :global_developer_key_id
def initialize(developer_key)
@global_developer_key_id = developer_key.global_id
end
end
def fake_access_token_for(developer_key)
if developer_key.present?
FakeAccessToken.new(developer_key)
end
end
def initialize(user:, acting_as:, access_token: nil, developer_key: nil, root_account:, oauth_host:)
@user = user # logged in user
@acting_as = acting_as # user being acted as
@access_token = access_token || fake_access_token_for(developer_key) # "access token" used to authenticate the logged in user, if any
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
@root_account = root_account # domain root account where the request occurred
@oauth_host = oauth_host # host against which inst-fs should oauth the user
end
def fingerprint
# note: this does _not_ incorporate the users' updated_at values like
# putting the user object in the cache key would, because this fingerprint
# is not intended to differentiate caches of information _about_ the user.
# just to differentiate caches _across_ user identities.
Digest::MD5.hexdigest("#{@user&.global_id}|#{@acting_as&.global_id}|#{@oauth_host}")
end
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
def instfs_options(attachment, extras={})
{
user: @user,
acting_as: @acting_as,
access_token: @access_token,
root_account: @root_account,
oauth_host: @oauth_host,
expires_in: attachment.url_ttl,
}.merge(extras)
end
def download_url(attachment)
return nil unless attachment
if attachment.instfs_hosted?
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
options = instfs_options(attachment, download: true)
InstFS.authenticated_url(attachment, options)
else
# s3 doesn't distinguish authenticated and public urls
attachment.public_download_url
end
end
def inline_url(attachment)
return nil unless attachment
if attachment.instfs_hosted?
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
options = instfs_options(attachment, download: false)
InstFS.authenticated_url(attachment, options)
else
# s3 doesn't distinguish authenticated and public urls
attachment.public_inline_url
end
end
def thumbnail_url(attachment, options={})
return nil unless attachment
if !Attachment.skip_thumbnails && attachment.instfs_hosted? && attachment.thumbnailable?
legacy api claims in inst-fs jwts for API clients fixes RECNVS-471 fixes RECNVS-479 allows API requests from access tokens issued by whitelisted developer keys to receive additional claims in the JWTs of inst-fs links in the response. these additional claims are a workaround to cause inst-fs to accept the link as if authenticated despite the client not having an inst-fs session or presenting inst-fs with the access token. updated API clients will need to present their API token when accessing inst-fs links. once the clients associated with a developer key are updated, the developer key will be removed from the whitelist. this is only a temporary workaround. test-plan: - have inst-fs configured and enabled with your canvas instance - generate a new access token for your user - in the rails console of your canvas instance, set: Setting.set('instfs.whitelist_all_developer_keys', 'true') - using something without a session, like postman, POST to /api/v1/courses/:course_id/files with a valid preflight and authenticated via the access token (e.g. using the `Authorization` header) - the `upload_url` in the response should be an inst-fs link - the `upload_url` should include a `token` query parameter with a JWT as the value - decoding the JWT from the `upload_url`, it should include `legacy_api_developer_key_id` and a `legacy_api_root_account_id` claims - in the rails console of your canvas instance: Setting.remove('instfs.whitelist_all_developer_keys') - repeat the upload preflight attempt from above - this time, the JWT should not include the `legacy_api_*` claims Change-Id: I911d18c031d9ba90de808e260e4644beaef69ff9 Reviewed-on: https://gerrit.instructure.com/151690 Tested-by: Jenkins Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> QA-Review: Collin Parrish <cparrish@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
2018-05-30 00:40:39 +08:00
options = instfs_options(attachment, geometry: options[:size])
InstFS.authenticated_thumbnail_url(attachment, options)
else
attachment.thumbnail_url(options)
end
end
end