Skip to content

Commit

Permalink
add success/fail for endpoint, update spec
Browse files Browse the repository at this point in the history
  • Loading branch information
peetucket committed Dec 6, 2023
1 parent 58cad31 commit 7583b28
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 109 deletions.
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ GEM
zip_tricks (>= 4.2.1, < 6.0)

PLATFORMS
x86_64-darwin-19
x86_64-darwin-20
x86_64-darwin-22
x86_64-linux
Expand Down
25 changes: 17 additions & 8 deletions app/controllers/iiif/auth/v2/probe_service_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,23 @@ module V2
# https://iiif.io/api/auth/2.0/#probe-service
class ProbeServiceController < ApplicationController
def show
# The HTTP status code that the client should expect to receive if it were to issue
# the same request to the resource
status = 200
response = {
'@context' => 'http://iiif.io/api/auth/2/context.json',
type: 'AuthProbeResult2',
status:
}
stacks_uri = params[:id] # this is a fully qualified URI to the resource on the stacks that the user is requesting access to
druid, file_name = stacks_uri.split('/').last(2) # need the druid (without prefix) and the filename in order to check for access

file = StacksFile.new(id: druid.delete_prefix('druid:'), file_name:, download: true)

response = { '@context': 'http://iiif.io/api/auth/2/context.json', type: 'AuthProbeResult2' }

if can? :access, file
response.merge!(status: 200)
else
# TODO: check restrictions on file object and include details in response e.g. like in MediaController#hash_for_auth_check
message = {
heading: { en: ["You can't see this"] },
note: { en: ["Sorry"] }
}
response.merge!(status: 401, message:)
end

render json: response
end
Expand Down
3 changes: 2 additions & 1 deletion app/models/stacks_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,6 @@ def druid_parts
def stacks_rights
@stacks_rights ||= StacksRights.new(id:, file_name:)
end
delegate :rights, :cocina_rights, to: :stacks_rights
delegate :rights, :cocina_rights, :restricted_by_location?, :stanford_restricted?, :embargoed?,
:embargo_release_date, :location, to: :stacks_rights
end
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,8 @@
get '/image/auth/:id/:file_name.:format' => 'legacy_image_service#show'
get '/image/auth/:id/:file_name' => 'legacy_image_service#show'
end

# IIIF Probe Service
get '/iiif/auth/v2/probe' => 'iiif/auth/v2/probe_service#show'

end
154 changes: 54 additions & 100 deletions spec/requests/iiif/auth/v2/probe_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,118 +3,72 @@
require 'rails_helper'

RSpec.describe 'IIIF auth v2 probe service' do
context 'when the user has access to the resource' do
before do
get '/iiif/auth/v2/probe/bc123df456'
end
end

describe '#create' do
context 'when messageId is sent (browser-based interaction)' do
let(:user) { User.new id: 'xyz', webauth_user: true }

before do
get '/image/iiif/token?origin=http://example.edu/&messageId=1'
end
let(:id) { 'bb461xx1037' }
let(:file_name) { 'SC0193_1982-013_b06_f01_1981-09-29.pdf' }
let(:stacks_uri) { "https://stacks-uat.stanford.edu/file/druid:#{id}/#{file_name}" }
let(:user) { instance_double(User, locations: [], webauth_user: false, stanford?: false, cdl_tokens: []) }
let(:ability) { Ability.new(user) }

it 'wipes out the X-Frame-Options header' do
expect(response.headers['X-Frame-Options']).to eq ''
end
# TODO: figure out how to correctly mock Ability object so it doesn't actually try to hit PURL to get rights and parse

it 'assigns the message and origin parameters' do
expect(response.response_code).to eq 200
expect(assigns(:origin)).to eq 'http://example.edu/'
expect(assigns(:message)).to include messageId: '1', accessToken: be_present
end

context 'when the format is js' do
before do
get '/image/iiif/token.js?origin=http://example.edu/&messageId=1'
end

it 'renders HTML anyway' do
expect(response.body).to match(/<html/)
end
end
before do
get "/iiif/auth/v2/probe?id=#{stacks_uri}"
#allow(ApplicationController).to receive(:current_ability).and_return(ability)
end

context 'when the origin parameter is missing' do
it 'returns a 400 error' do
expect { get '/image/iiif/token?messageId=1' }.to raise_error ActionController::ParameterMissing
end
end
context 'when the user has access to the resource' do
let(:file) do
instance_double(
StacksFile,
id:,
file_name:,
restricted_by_location?: false,
stanford_restricted?: false,
embargoed?: false,
download: true
)
end

describe 'JSON API interaction' do
context 'when HTML format is requested' do
before do
get '/image/iiif/token'
end

it 'redirects to JSON' do
expect(response).to redirect_to format: :js
end
end

context 'with a user' do
before do
get '/image/iiif/token.js'
end

let(:user) { User.new id: 'xyz', webauth_user: true }

it 'returns the token response' do
expect(response.status).to eq 200

data = response.parsed_body
expect(data['accessToken']).not_to be_blank
expect(data['tokenType']).to eq 'Bearer'
expect(data['expiresIn']).to be > 0
end
end

context 'with an anonymous user' do
before do
get '/image/iiif/token.js'
end

it 'returns the error response' do
expect(response.status).to eq 401
before do
allow(ability).to receive(:can?).with(:access, file).and_return(false)
end

expect(response.parsed_body['error']).to eq 'missingCredentials'
end
end
it 'returns a success response' do
expect(response).to have_http_status :ok
expect(response.parsed_body).to include({
"@context" => "http://iiif.io/api/auth/2/context.json",
"type" => "AuthProbeResult2",
"status" => 200
})
end
end

describe '#create_for_item' do
it 'returns an error response' do
get '/image/iiif/token/whatever.js'

expect(response.status).to eq 401

expect(response.parsed_body['error']).to eq 'missingCredentials'
context 'when the user does not have access to the resource' do
let(:file) do
instance_double(
StacksFile,
id:,
file_name:,
restricted_by_location?: false,
stanford_restricted?: true,
embargoed?: false,
download: true
)
end

context 'with a token for the item' do
let(:user) do
User.new(
id: 'xyz',
jwt_tokens: jwt_tokens.map do |payload|
JWT.encode(payload, Settings.cdl.jwt.secret, Settings.cdl.jwt.algorithm)
end
)
end

let(:jwt_tokens) do
[
{ jti: 'a', aud: 'whatever', sub: 'xyz', exp: (Time.zone.now + 1.hour).to_i }
]
end
before do
allow(ability).to receive(:can?).with(:access, file).and_return(false)
end

it 'calls the ordinary create method' do
get '/image/iiif/token/whatever.js'
expect(response.parsed_body).to include({ 'tokenType' => 'Bearer' })
end
it 'returns a not authorized response' do
expect(response).to have_http_status :ok # NOTE: response status from service is OK, status of the resource is in the response body
expect(response.parsed_body).to include({
"@context" => "http://iiif.io/api/auth/2/context.json",
"type" => "AuthProbeResult2",
"status" => 401,
"heading" => { "en" => ["You can't see this"] },
"note" => { "en" => ["Sorry"] }
})
end
end
end

0 comments on commit 7583b28

Please sign in to comment.