Add authentication for immersive reader

Test Plan:
  - Given the proper credentials in dynamic_settings.yml, calling
    /api/v1/immersive_reader/authenticate works

closes COREFE-263

flag = none

Change-Id: I2f42772691d7d64fb79229585ee9d008fa2ce2b6
Reviewed-on: https://gerrit.instructure.com/209911
Tested-by: Jenkins
Reviewed-by: Cameron Matheson <cameron@instructure.com>
QA-Review: Clay Diffrient <cdiffrient@instructure.com>
Product-Review: Clay Diffrient <cdiffrient@instructure.com>
This commit is contained in:
Clay Diffrient 2019-09-17 13:37:58 -06:00
parent 9396edaa41
commit efe559d030
3 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,67 @@
#
# Copyright (C) 2019 - 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/>.
#
# @API Immersive Reader
# @beta
#
# This API requires Immersive Reader to be configured
class ImmersiveReaderController < ApplicationController
before_action :require_user
before_action :require_config
def ir_config
@ir_config ||= YAML.load(Canvas::DynamicSettings.find(tree: :private)['immersive_reader.yml'] || '{}')
end
def require_config
return render json: { message: 'Service not found' }, status: :not_found unless ir_config.present?
end
def service_url
"https://login.windows.net/#{ir_config[:ir_tenant_id]}/oauth2/token"
end
def headers
{ "content-type": "application/x-www-form-urlencoded" }
end
def form
{
grant_type: "client_credentials",
client_id: ir_config[:ir_client_id],
client_secret: ir_config[:ir_client_secret],
resource: "https://cognitiveservices.azure.com/"
}
end
def authenticate
response = CanvasHttp.post(service_url, headers, form_data: form)
if response && response.code == '200'
parsed = JSON.parse(response.body)
render json: {
token: parsed["access_token"],
subdomain: ir_config[:ir_subdomain]
}
else
message = "Error connecting to cognitive services #{response}"
raise ServiceError, message
end
end
end

View File

@ -1623,6 +1623,10 @@ CanvasRails::Application.routes.draw do
post 'image_selection/:id', action: :image_selection
end
scope(controller: :immersive_reader) do
get 'immersive_reader/authenticate', action: :authenticate
end
scope(controller: :search) do
get 'search/rubrics', action: 'rubrics', as: 'search_rubrics'
get 'search/recipients', action: 'recipients', as: 'search_recipients'

View File

@ -0,0 +1,57 @@
#
# Copyright (C) 2019 - 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/>.
#
require 'spec_helper'
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true)
describe ImmersiveReaderController do
it 'should require a user be logged in' do
get 'authenticate'
assert_unauthorized
end
it 'should require the plugin be configured' do
user_model
user_session(@user)
get 'authenticate'
assert_status(404)
end
it 'should authenticate with cognitive services' do
user_model
user_session(@user)
stub_request(:post, 'https://login.windows.net')
allow(controller).to receive(:ir_config).and_return(
{
ir_tenant_id: 'faketenantid',
ir_client_id: 'fakeclientid',
ir_client_secret: 'fakesecret',
ir_subdomain: 'fakesub'
}
)
get 'authenticate'
expect(WebMock).to have_requested(:post, 'https://login.windows.net/faketenantid/oauth2/token')
.with(
body:
'grant_type=client_credentials&client_id=fakeclientid&client_secret=fakesecret&resource=https%3A%2F%2Fcognitiveservices.azure.com%2F',
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }
)
.once
end
end