diff --git a/Gemfile.lock b/Gemfile.lock index 902ced6e..a39229c8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -405,6 +405,7 @@ GEM hashdiff (>= 0.4.0, < 2.0.0) PLATFORMS + x86_64-darwin-23 x86_64-linux DEPENDENCIES @@ -463,4 +464,4 @@ DEPENDENCIES webmock (~> 3.19.1) BUNDLED WITH - 2.3.15 + 2.4.22 diff --git a/controllers/dereference_resource_controller.rb b/controllers/dereference_resource_controller.rb index 77de82f9..8b69efdb 100644 --- a/controllers/dereference_resource_controller.rb +++ b/controllers/dereference_resource_controller.rb @@ -1,5 +1,3 @@ -require_relative '../test/test_case' - use Rack::ContentNegotiation class DereferenceResourceController < ApplicationController diff --git a/controllers/search_controller.rb b/controllers/search_controller.rb index 9a354f08..9f701714 100644 --- a/controllers/search_controller.rb +++ b/controllers/search_controller.rb @@ -22,7 +22,7 @@ class SearchController < ApplicationController format = params.fetch("hasOntologyLanguage", "").split(',') is_of_type = params.fetch("isOfType", "").split(',') has_format = params.fetch("hasFormat", "").split(',') - visibility = params["visibility"]&.presence || "public" + visibility = params["visibility"] show_views = params["show_views"] == 'true' sort = params.fetch("sort", "score desc, ontology_name_sort asc, ontology_acronym_sort asc") page, page_size = page_params @@ -30,12 +30,12 @@ class SearchController < ApplicationController fq = [ 'resource_model:"ontology_submission"', 'submissionStatus_txt:ERROR_* OR submissionStatus_txt:"RDF" OR submissionStatus_txt:"UPLOADED"', - "ontology_viewingRestriction_t:#{visibility}", groups.map { |x| "ontology_group_txt:\"http://data.bioontology.org/groups/#{x.upcase}\"" }.join(' OR '), categories.map { |x| "ontology_hasDomain_txt:\"http://data.bioontology.org/categories/#{x.upcase}\"" }.join(' OR '), languages.map { |x| "naturalLanguage_txt:\"#{x.downcase}\"" }.join(' OR '), ] + fq << "ontology_viewingRestriction_t:#{visibility}" unless visibility.blank? fq << "!ontology_viewOf_t:*" unless show_views fq << format.map { |x| "hasOntologyLanguage_t:\"http://data.bioontology.org/ontology_formats/#{x}\"" }.join(' OR ') unless format.blank? @@ -75,7 +75,15 @@ class SearchController < ApplicationController old_resource_id = acronyms_ids[acronym] old_id = old_resource_id.split('/').last.to_i rescue 0 - if acronym.blank? || old_id && id && (id <= old_id) + already_found = (old_id && id && (id <= old_id)) + not_restricted = (doc["ontology_viewingRestriction_t"]&.eql?('public') || current_user&.admin?) + user_not_restricted = not_restricted || + Array(doc["ontology_viewingRestriction_txt"]).any? {|u| u.split(' ').last == current_user&.username} || + Array(doc["ontology_acl_txt"]).any? {|u| u.split(' ').last == current_user&.username} + + user_restricted = !user_not_restricted + + if acronym.blank? || already_found || user_restricted total_found -= 1 next end @@ -99,10 +107,26 @@ class SearchController < ApplicationController get '/content' do query = params[:query] || params[:q] page, page_size = page_params + ontologies = params.fetch("ontologies", "").split(',') + + unless current_user&.admin? + restricted_acronyms = restricted_ontologies_to_acronyms(params) + ontologies = ontologies.empty? ? restricted_acronyms : ontologies & restricted_acronyms + end + + types = params.fetch("types", "").split(',') qf = params.fetch("qf", "") + qf = [ + "ontology_t^100 resource_id^10", + "http___www.w3.org_2004_02_skos_core_prefLabel_txt^30", + "http___www.w3.org_2004_02_skos_core_prefLabel_t^30", + "http___www.w3.org_2000_01_rdf-schema_label_txt^30", + "http___www.w3.org_2000_01_rdf-schema_label_t^30", + ].join(' ') if qf.blank? + fq = [] fq << ontologies.map { |x| "ontology_t:\"#{x}\"" }.join(' OR ') unless ontologies.blank? @@ -117,7 +141,7 @@ class SearchController < ApplicationController docs = resp["response"]["docs"] - reply 200,page_object(docs, total_found) + reply 200, page_object(docs, total_found) end end diff --git a/docker-compose.yml b/docker-compose.yml index 747b4735..370615a6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,10 +80,12 @@ services: - 4store solr-ut: - image: solr:8 - ports: - - 8983:8983 - command: bin/solr start -cloud -f + image: solr:8 + ports: + - 8983:8983 + command: bin/solr start -cloud -f + # volumes: + #- solr_data:/var/solr/data agraph-ut: image: franzinc/agraph:v8.1.0 platform: linux/amd64 diff --git a/test/controllers/test_search_models_controller.rb b/test/controllers/test_search_models_controller.rb index 851c7a31..6b9cef29 100644 --- a/test/controllers/test_search_models_controller.rb +++ b/test/controllers/test_search_models_controller.rb @@ -55,6 +55,77 @@ def test_collection_search assert_equal 2, res['response']['numFound'] end + def test_search_security + count, acronyms, bro = LinkedData::SampleData::Ontology.create_ontologies_and_submissions({ + process_submission: true, + process_options: { process_rdf: true, extract_metadata: false, generate_missing_labels: false}, + acronym: "BROSEARCHTEST", + name: "BRO Search Test", + file_path: "./test/data/ontology_files/BRO_v3.2.owl", + ont_count: 1, + submission_count: 1, + ontology_type: "VALUE_SET_COLLECTION" + }) + + count, acronyms, mccl = LinkedData::SampleData::Ontology.create_ontologies_and_submissions({ + process_submission: true, + process_options: { process_rdf: true, extract_metadata: false, generate_missing_labels: false}, + acronym: "MCCLSEARCHTEST", + name: "MCCL Search Test", + file_path: "./test/data/ontology_files/CellLine_OWL_BioPortal_v1.0.owl", + ont_count: 1, + submission_count: 1 + }) + + + subs = LinkedData::Models::OntologySubmission.all + subs.each do |s| + s.bring_remaining + s.index_all_data(Logger.new($stdout)) + end + + + allowed_user = User.new({ + username: "allowed", + email: "test1@example.org", + password: "12345" + }) + allowed_user.save + + blocked_user = User.new({ + username: "blocked", + email: "test2@example.org", + password: "12345" + }) + blocked_user.save + + bro = bro.first + bro.bring_remaining + bro.acl = [allowed_user] + bro.viewingRestriction = "private" + bro.save + + self.class.enable_security + get "/search/ontologies?query=#{bro.acronym}&apikey=#{blocked_user.apikey}" + response = MultiJson.load(last_response.body)["collection"] + assert_empty response.select{|x| x["ontology_acronym_text"].eql?(bro.acronym)} + + get "/search/ontologies/content?q=*Research_Lab_Management*&apikey=#{blocked_user.apikey}" + assert last_response.ok? + res = MultiJson.load(last_response.body) + assert_equal 0, res['totalCount'] + + get "/search/ontologies?query=#{bro.acronym}&apikey=#{allowed_user.apikey}" + response = MultiJson.load(last_response.body)["collection"] + refute_empty response.select{|x| x["ontology_acronym_text"].eql?(bro.acronym)} + + get "/search/ontologies/content?q=*Research_Lab_Management*&apikey=#{allowed_user.apikey}" + assert last_response.ok? + res = MultiJson.load(last_response.body) + assert_equal 1, res['totalCount'] + + self.class.reset_security(false) + end def test_ontology_metadata_search count, acronyms, bro = LinkedData::SampleData::Ontology.create_ontologies_and_submissions({