|
19 | 19 | root_uri.query = launch_params.to_query |
20 | 20 | root_uri.to_s |
21 | 21 | end |
| 22 | + let(:mock_roles) { [LtiDeployment::LTI_ROLES[:instructor]] } |
| 23 | + |
| 24 | + def create_pub_jwk |
| 25 | + @create_pub_jwk ||= JWT::JWK.new(OpenSSL::PKey::RSA.new(1024)) |
| 26 | + end |
| 27 | + |
| 28 | + def generate_payload(roles, nonce) |
| 29 | + { aud: client_id, |
| 30 | + iss: host, |
| 31 | + nonce: nonce, |
| 32 | + LtiDeployment::LTI_CLAIMS[:deployment_id] => 'some_deployment_id', |
| 33 | + LtiDeployment::LTI_CLAIMS[:context] => { label: 'csc108', title: 'test' }, |
| 34 | + LtiDeployment::LTI_CLAIMS[:custom] => { course_id: 1, user_id: 1 }, |
| 35 | + LtiDeployment::LTI_CLAIMS[:user_id] => 'some_user_id', |
| 36 | + LtiDeployment::LTI_CLAIMS[:roles] => roles } |
| 37 | + end |
| 38 | + |
| 39 | + def generate_lti_jwt(roles, nonce) |
| 40 | + payload = generate_payload(roles, nonce) |
| 41 | + pub_jwk = create_pub_jwk |
| 42 | + JWT.encode(payload, pub_jwk.keypair, 'RS256', { kid: pub_jwk.kid }) |
| 43 | + end |
| 44 | + |
22 | 45 | describe '#launch' do |
23 | 46 | context 'when launching with invalid parameters' do |
24 | 47 | let(:lti_message_hint) { 'opaque string' } |
|
98 | 121 | let(:nonce) { rand(10 ** 30).to_s.rjust(30, '0') } |
99 | 122 |
|
100 | 123 | before do |
| 124 | + stub_request(:get, jwk_url).to_return(status: 200, body: { keys: [create_pub_jwk.export] }.to_json) |
| 125 | + |
101 | 126 | lti_launch_data = {} |
102 | 127 | lti_launch_data[:client_id] = client_id |
103 | 128 | lti_launch_data[:iss] = host |
|
129 | 154 | end |
130 | 155 |
|
131 | 156 | context 'with correct parameters' do |
132 | | - let(:payload) do |
133 | | - { aud: client_id, |
134 | | - iss: host, |
135 | | - nonce: nonce, |
136 | | - LtiDeployment::LTI_CLAIMS[:deployment_id] => 'some_deployment_id', |
137 | | - LtiDeployment::LTI_CLAIMS[:context] => { |
138 | | - label: 'csc108', |
139 | | - title: 'test' |
140 | | - }, |
141 | | - LtiDeployment::LTI_CLAIMS[:custom] => { |
142 | | - course_id: 1, |
143 | | - user_id: 1 |
144 | | - }, |
145 | | - LtiDeployment::LTI_CLAIMS[:user_id] => 'some_user_id' } |
146 | | - end |
147 | | - let(:pub_jwk) { JWT::JWK.new(OpenSSL::PKey::RSA.new(1024)) } |
148 | | - let(:lti_jwt) { JWT.encode(payload, pub_jwk.keypair, 'RS256', { kid: pub_jwk.kid }) } |
| 157 | + let(:lti_jwt) { generate_lti_jwt(mock_roles, nonce) } |
149 | 158 |
|
150 | 159 | before do |
151 | 160 | session[:client_id] = client_id |
152 | | - stub_request(:get, jwk_url).to_return(status: 200, body: { keys: [pub_jwk.export] }.to_json) |
153 | 161 | end |
154 | 162 |
|
155 | 163 | it 'successfully decodes the jwt and redirects' do |
|
190 | 198 | end |
191 | 199 | end |
192 | 200 |
|
| 201 | + context 'with LTI role authorization' do |
| 202 | + let(:admin_lti_uri) { LtiDeployment::LTI_ROLES[:admin] } |
| 203 | + let(:student_lti_uri) { LtiDeployment::LTI_ROLES[:learner] } |
| 204 | + let(:ta_lti_uri) { LtiDeployment::LTI_ROLES[:ta] } |
| 205 | + let(:instructor_lti_uri) { LtiDeployment::LTI_ROLES[:instructor] } |
| 206 | + |
| 207 | + context 'when LTI role is Instructor' do |
| 208 | + let(:lti_jwt) { generate_lti_jwt([instructor_lti_uri], nonce) } |
| 209 | + |
| 210 | + it 'redirects to course chooser' do |
| 211 | + request.headers['Referer'] = host |
| 212 | + post_as instructor, :redirect_login, params: { state: session.id.to_s, id_token: lti_jwt } |
| 213 | + expect(response).to redirect_to(choose_course_lti_deployment_path(LtiDeployment.first)) |
| 214 | + end |
| 215 | + end |
| 216 | + |
| 217 | + context 'when LTI role is Admin' do |
| 218 | + let(:lti_jwt) { generate_lti_jwt([admin_lti_uri], nonce) } |
| 219 | + |
| 220 | + it 'redirects to course chooser' do |
| 221 | + request.headers['Referer'] = host |
| 222 | + post_as instructor, :redirect_login, params: { state: session.id.to_s, id_token: lti_jwt } |
| 223 | + expect(response).to redirect_to(choose_course_lti_deployment_path(LtiDeployment.first)) |
| 224 | + end |
| 225 | + end |
| 226 | + |
| 227 | + context 'when LTI role is Student' do |
| 228 | + let(:lti_jwt) { generate_lti_jwt([student_lti_uri], nonce) } |
| 229 | + |
| 230 | + it 'redirects to "not set up" page' do |
| 231 | + request.headers['Referer'] = host |
| 232 | + post_as instructor, :redirect_login, params: { state: session.id.to_s, id_token: lti_jwt } |
| 233 | + expect(response).to redirect_to(course_not_set_up_lti_deployment_path(LtiDeployment.first)) |
| 234 | + end |
| 235 | + end |
| 236 | + |
| 237 | + context 'when LTI role is TA (even with Instructor claim)' do |
| 238 | + let(:lti_jwt) { generate_lti_jwt([ta_lti_uri, instructor_lti_uri], nonce) } |
| 239 | + |
| 240 | + it 'redirects to "not set up" page' do |
| 241 | + request.headers['Referer'] = host |
| 242 | + post_as instructor, :redirect_login, params: { state: session.id.to_s, id_token: lti_jwt } |
| 243 | + expect(response).to redirect_to(course_not_set_up_lti_deployment_path(LtiDeployment.first)) |
| 244 | + end |
| 245 | + end |
| 246 | + end |
| 247 | + |
193 | 248 | context 'get' do |
194 | 249 | it 'returns an error if not logged in' do |
195 | 250 | request.headers['Referer'] = host |
|
212 | 267 | lms_course_name: 'Introduction to Computer Science', |
213 | 268 | lms_course_label: 'CSC108', |
214 | 269 | lms_course_id: 1, |
215 | | - lti_user_id: 'user_id' } |
| 270 | + lti_user_id: 'user_id', |
| 271 | + user_roles: mock_roles } |
216 | 272 | end |
217 | 273 | let(:payload) do |
218 | 274 | { aud: client_id, |
|
225 | 281 | LtiDeployment::LTI_CLAIMS[:custom] => { |
226 | 282 | course_id: 1, |
227 | 283 | user_id: 1 |
228 | | - } } |
| 284 | + }, |
| 285 | + LtiDeployment::LTI_CLAIMS[:roles] => mock_roles } |
229 | 286 | end |
230 | | - let(:pub_jwk) { JWT::JWK.new(OpenSSL::PKey::RSA.new(1024)) } |
231 | | - let(:lti_jwt) { JWT.encode(payload, pub_jwk.keypair, 'RS256', { kid: pub_jwk.kid }) } |
232 | 287 |
|
233 | 288 | before do |
234 | 289 | cookies.permanent.encrypted[:lti_data] = { value: JSON.generate(lti_data), expires: 5.minutes.from_now } |
235 | | - stub_request(:get, jwk_url).to_return(status: 200, body: { keys: [pub_jwk.export] }.to_json) |
236 | 290 | end |
237 | 291 |
|
238 | 292 | it 'successfully decodes the jwt and redirects' do |
|
0 commit comments