diff --git a/freeze.txt b/freeze.txt index fc3c2e97a1..0c7a47a7d1 100644 --- a/freeze.txt +++ b/freeze.txt @@ -90,47 +90,47 @@ importlib-resources==5.4.0 infinity==1.4 intervals==0.8.0 invenio-access==1.1.0 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_accounts&subdirectory=modules/invenio-accounts +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_accounts&subdirectory=modules/invenio-accounts invenio-admin==1.1.2 invenio-app==1.1.0 invenio-assets==1.0.0 invenio-base==1.0.2 invenio-cache==1.0.0 invenio-celery==1.1.3 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_communities&subdirectory=modules/invenio-communities +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_communities&subdirectory=modules/invenio-communities invenio-config==1.0.0 invenio-csl-rest==1.0.0a1 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_db&subdirectory=modules/invenio-db --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_deposit&subdirectory=modules/invenio-deposit --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_files_rest&subdirectory=modules/invenio-files-rest +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_db&subdirectory=modules/invenio-db +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_deposit&subdirectory=modules/invenio-deposit +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_files_rest&subdirectory=modules/invenio-files-rest invenio-formatter==1.0.0b3 invenio-i18n==1.0.0 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_iiif&subdirectory=modules/invenio-iiif --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_indexer&subdirectory=modules/invenio-indexer +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_iiif&subdirectory=modules/invenio-iiif +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_indexer&subdirectory=modules/invenio-indexer invenio-jsonschemas==1.0.0 invenio-logging==1.0.0b3 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_mail&subdirectory=modules/invenio-mail +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_mail&subdirectory=modules/invenio-mail invenio-marc21==1.0.0a8 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oaiharvester&subdirectory=modules/invenio-oaiharvester --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oaiserver&subdirectory=modules/invenio-oaiserver --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oauth2server&subdirectory=modules/invenio-oauth2server +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oaiharvester&subdirectory=modules/invenio-oaiharvester +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oaiserver&subdirectory=modules/invenio-oaiserver +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_oauth2server&subdirectory=modules/invenio-oauth2server invenio-oauthclient==1.0.0 invenio-pidrelations==1.0.0a4 invenio-pidstore==1.0.0 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_previewer&subdirectory=modules/invenio-previewer +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_previewer&subdirectory=modules/invenio-previewer invenio-query-parser==0.6.0 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_queues&subdirectory=modules/invenio-queues --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_records&subdirectory=modules/invenio-records +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_queues&subdirectory=modules/invenio-queues +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_records&subdirectory=modules/invenio-records invenio-records-files==1.0.0a10 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_records_rest&subdirectory=modules/invenio-records-rest +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_records_rest&subdirectory=modules/invenio-records-rest invenio-records-ui==1.0.0 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_resourcesyncclient&subdirectory=modules/invenio-resourcesyncclient --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_resourcesyncserver&subdirectory=modules/invenio-resourcesyncserver +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_resourcesyncclient&subdirectory=modules/invenio-resourcesyncclient +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_resourcesyncserver&subdirectory=modules/invenio-resourcesyncserver invenio-rest==1.1.2 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_s3&subdirectory=modules/invenio-s3 +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_s3&subdirectory=modules/invenio-s3 -e git+https://github.com/RCOSDP/invenio-search.git@cff9744c5dc651893a9c51672c5b8da9adc21e16#egg=invenio_search -e git+https://github.com/RCOSDP/invenio-search-ui.git@74bd3b2990ff27b39e01b6b31be9a0b5fda3dd0f#egg=invenio_search_ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_stats&subdirectory=modules/invenio-stats +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=invenio_stats&subdirectory=modules/invenio-stats invenio-theme==1.0.0b4 ipaddress==1.0.19 ipython==6.2.1 @@ -240,30 +240,30 @@ wcwidth==0.1.7 webargs==5.5.2 webassets==0.12.1 webencodings==0.5.1 --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_accounts&subdirectory=modules/weko-accounts --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_admin&subdirectory=modules/weko-admin --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_authors&subdirectory=modules/weko-authors --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_bulkupdate&subdirectory=modules/weko-bulkupdate --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_deposit&subdirectory=modules/weko-deposit --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_gridlayout&subdirectory=modules/weko-gridlayout --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_groups&subdirectory=modules/weko-groups --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_handle&subdirectory=modules/weko-handle --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_index_tree&subdirectory=modules/weko-index-tree --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_indextree_journal&subdirectory=modules/weko-indextree-journal --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_items_autofill&subdirectory=modules/weko-items-autofill --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_items_ui&subdirectory=modules/weko-items-ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_itemtypes_ui&subdirectory=modules/weko-itemtypes-ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_logging&subdirectory=modules/weko-logging --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_records&subdirectory=modules/weko-records --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_records_ui&subdirectory=modules/weko-records-ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_redis&subdirectory=modules/weko-redis --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_schema_ui&subdirectory=modules/weko-schema-ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_search_ui&subdirectory=modules/weko-search-ui --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_sitemap&subdirectory=modules/weko-sitemap --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_swordserver&subdirectory=modules/weko-swordserver --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_theme&subdirectory=modules/weko-theme --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_user_profiles&subdirectory=modules/weko-user-profiles --e git+https://mhaya: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@github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_workflow&subdirectory=modules/weko-workflow +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_accounts&subdirectory=modules/weko-accounts +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_admin&subdirectory=modules/weko-admin +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_authors&subdirectory=modules/weko-authors +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_bulkupdate&subdirectory=modules/weko-bulkupdate +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_deposit&subdirectory=modules/weko-deposit +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_gridlayout&subdirectory=modules/weko-gridlayout +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_groups&subdirectory=modules/weko-groups +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_handle&subdirectory=modules/weko-handle +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_index_tree&subdirectory=modules/weko-index-tree +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_indextree_journal&subdirectory=modules/weko-indextree-journal +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_items_autofill&subdirectory=modules/weko-items-autofill +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_items_ui&subdirectory=modules/weko-items-ui +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_itemtypes_ui&subdirectory=modules/weko-itemtypes-ui +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_logging&subdirectory=modules/weko-logging +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_records&subdirectory=modules/weko-records +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_records_ui&subdirectory=modules/weko-records-ui +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_redis&subdirectory=modules/weko-redis +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_schema_ui&subdirectory=modules/weko-schema-ui +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_search_ui&subdirectory=modules/weko-search-ui +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_sitemap&subdirectory=modules/weko-sitemap +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_swordserver&subdirectory=modules/weko-swordserver +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_theme&subdirectory=modules/weko-theme +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_user_profiles&subdirectory=modules/weko-user-profiles +-e git+https://github.com/RCOSDP/weko.git@55eea912ab9768a0fdf4430420bf2b00eadac049#egg=weko_workflow&subdirectory=modules/weko-workflow Werkzeug==0.15.2 whichcraft==0.4.1 WTForms==2.1 diff --git a/modules/invenio-files-rest/invenio_files_rest/alembic/faf4faa08601_add_column_file_readonly_keys.py b/modules/invenio-files-rest/invenio_files_rest/alembic/faf4faa08601_add_column_file_readonly_keys.py new file mode 100644 index 0000000000..18f38c2c2c --- /dev/null +++ b/modules/invenio-files-rest/invenio_files_rest/alembic/faf4faa08601_add_column_file_readonly_keys.py @@ -0,0 +1,30 @@ +# +# This file is part of Invenio. +# Copyright (C) 2016-2018 CERN. +# +# Invenio is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +"""add column file readonly_keys""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'faf4faa08601' +down_revision = '8644b32a3eec' +branch_labels = () +depends_on = None + + +def upgrade(): + """Upgrade database.""" + op.add_column('files_location', sa.Column('readonly_access_key', sa.String(length=128), nullable=True)) + op.add_column('files_location', sa.Column('readonly_secret_key', sa.String(length=128), nullable=True)) + + +def downgrade(): + """Downgrade database.""" + op.drop_column('files_location', 'readonly_secret_key') + op.drop_column('files_location', 'readonly_access_key') diff --git a/modules/weko-gridlayout/tests/test_views.py b/modules/weko-gridlayout/tests/test_views.py index 3ad788148b..29cf512c91 100644 --- a/modules/weko-gridlayout/tests/test_views.py +++ b/modules/weko-gridlayout/tests/test_views.py @@ -598,7 +598,9 @@ def test_delete_widget_design_page(client, users): ] @pytest.mark.parametrize('id, status_code', user_results2) def test_load_widget_type(client, users, id, status_code): - login_user_via_session(client=client, email=users[id]['obj'].email) + # Log in with "email": "obj" of users[4] (generaluser) is the sysadmin + # object in the users fixture. + login_user_via_session(client=client, email=users[id]['email']) res = client.get( url_for("weko_gridlayout_api.load_widget_type"), headers={"Content-Type": "application/json"} @@ -972,33 +974,37 @@ def test_upload_file(client, users, communities): # def uploaded_file(filename, community_id=0): -user_results2 = [ - (0, 403), - (1, 200), - (2, 200), - (3, 403), - (4, 403), +# The files are shown on the public pages, so anyone - including users who +# are not logged in - can get them. +uploaded_file_users = [ + None, # not logged in + 0, # Contributor + 1, # Repository Administrator + 2, # System Administrator + 3, # Community Administrator + 7, # user without any role ] -@pytest.mark.parametrize('id, status_code', user_results2) -def test_uploaded_file(client, users, id, status_code): - login_user_via_session(client=client, email=users[id]["email"]) - with patch('weko_gridlayout.views.WidgetBucket.get_file', return_value="test"): - res = client.get( - url_for("weko_gridlayout.uploaded_file", community_id="Root Index", filename="file") - ) - assert res.status_code == status_code - assert res.get_data(as_text=True) == "test" - - -def test_uploaded_file(client, communities): +@pytest.mark.parametrize('id', uploaded_file_users) +@pytest.mark.parametrize('community_id', ["Root Index", "comm1"]) +def test_uploaded_file(client, users, communities, id, community_id): + if id is not None: + login_user_via_session(client=client, email=users[id]["email"]) # The view returns whatever get_file() gives it, so the stand-in has to be # something Flask can turn into a response - a function is not. - with patch('weko_gridlayout.views.WidgetBucket.get_file', return_value="test"): + with patch('weko_gridlayout.views.WidgetBucket.get_file', return_value="test") as get_file: res = client.get( - url_for("weko_gridlayout.uploaded_file", community_id="comm1", filename="file") + url_for("weko_gridlayout.uploaded_file", community_id=community_id, filename="file") ) assert res.status_code == 200 assert res.get_data(as_text=True) == "test" + get_file.assert_called_once_with("file", community_id) + + +def test_uploaded_file_without_community(client): + with patch('weko_gridlayout.views.WidgetBucket.get_file', return_value="test") as get_file: + res = client.get("/widget/uploaded/file") + assert res.status_code == 200 + get_file.assert_called_once_with("file", 0) # def unlocked_widget(): def test_unlocked_widget(client, users): diff --git a/modules/weko-gridlayout/weko_gridlayout/views.py b/modules/weko-gridlayout/weko_gridlayout/views.py index 5ff691ebdd..bfec595acb 100644 --- a/modules/weko-gridlayout/weko_gridlayout/views.py +++ b/modules/weko-gridlayout/weko_gridlayout/views.py @@ -611,12 +611,13 @@ def upload_file(community_id): @blueprint.route('/widget/uploaded//', methods=["GET"] ) -@roles_required([WEKO_ADMIN_PERMISSION_ROLE_SYSTEM, - WEKO_ADMIN_PERMISSION_ROLE_REPO, - WEKO_ADMIN_PERMISSION_ROLE_COMMUNITY]) def uploaded_file(filename, community_id=0): """Get widget static file. + The files are embedded in widgets (e.g. images in a free description + widget) and are loaded by the browser on the public pages, so this view + must be reachable without logging in. + :param filename: file name. :param community_id: community identifier. :return: diff --git a/modules/weko-records-ui/tests/test_utils.py b/modules/weko-records-ui/tests/test_utils.py index 706436243d..4bb62928b3 100644 --- a/modules/weko-records-ui/tests/test_utils.py +++ b/modules/weko-records-ui/tests/test_utils.py @@ -60,6 +60,7 @@ can_manage_secret_url, validate_token, validate_url_download, + ensure_url_record_matches, generate_one_time_download_url, parse_one_time_download_token, ) @@ -762,27 +763,50 @@ def test_parse_one_time_download_token(app): def test_is_private_index(app,records): indexer, results = records record = results[0]["record"] + # Regression: the fixture record belongs to a single public index. assert is_private_index(record)==False - data1 = [ - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - [0, 1, 2, 3, 4, 5, 6], - ] - with patch("weko_index_tree.api.Indexes.get_path_list", return_value=data1): - assert is_private_index(record) == False +# def is_private_index(record): +# .tox/c1/bin/pytest --cov=weko_records_ui tests/test_utils.py::test_is_private_index_decision_table -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp +@pytest.mark.parametrize( + "delegate_return, expected", + [ + pytest.param( + True, False, + id="rule1_at_least_one_fully_public_chain"), + pytest.param( + False, True, + id="rule2_no_fully_public_chain_eg_future_dated_or_nonpublic_ancestor"), + pytest.param( + None, True, + id="rule3_delegate_returns_none_eg_all_indexes_deleted"), + ], +) +def test_is_private_index_decision_table(delegate_return, expected): + with patch( + "weko_index_tree.api.Indexes.is_public_state_and_not_in_future", + return_value=delegate_return, + ) as mock_delegate: + assert is_private_index({"path": ["1", "2"]}) is expected + mock_delegate.assert_called_once_with(["1", "2"]) - data1 = [ - [0, 1, 2, 3, 4, 5, False], - ] - with patch("weko_index_tree.api.Indexes.get_path_list", return_value=data1): - assert is_private_index(record) == True +@pytest.mark.parametrize( + "record", + [ + pytest.param({"path": []}, id="rule4_empty_path_list"), + pytest.param({}, id="rule5_no_path_key_at_all"), + ], +) +def test_is_private_index_no_index_short_circuits(record): + # An item that belongs to no index at all must be treated as private + # without even querying Indexes.is_public_state_and_not_in_future(). + with patch( + "weko_index_tree.api.Indexes.is_public_state_and_not_in_future" + ) as mock_delegate: + assert is_private_index(record) is True + mock_delegate.assert_not_called() # def validate_download_record(record: dict): @@ -1480,6 +1504,13 @@ def test_validate_token(app, users): match = re.search(r'[?&]token=([^&]+)', url) onetime_token = match.group(1) assert validate_token(onetime_token, is_secret_url=False) is True + + # Cross-type reuse: a validly-signed secret-URL token must not + # validate via the onetime-URL path, and vice versa. + with app.test_request_context(): + assert validate_token(secret_token, is_secret_url=False) is False + assert validate_token(onetime_token, is_secret_url=True) is False + invalid_bytes = b'\xb2q\xff\x19\xaf\xfc\xc6T\x8bt\xd6\xf6\xc6 \ \x08D\xe7\xf3G;cN\x1bn|\xa2\x88\x01v\xed\x1cA_1' with app.test_request_context(): @@ -1564,6 +1595,8 @@ def test_convert_token_into_obj(vldt_token, app, users): @patch('weko_records_ui.utils.validate_download_record') def test_validate_url_download(vldt_record, vldt_file, is_enabled, vldt_token, app, db, users): + matching_record = {'recid': 1} + matching_filename = 'test.txt' with app.test_request_context(): secret_obj = FileSecretDownload.create( creator_id=1, @@ -1579,7 +1612,8 @@ def test_validate_url_download(vldt_record, vldt_file, is_enabled, vldt_token, is_enabled.return_value = True vldt_file.return_value = True vldt_record.return_value = True - assert validate_url_download('', '', secret_token, True) == (True, '') + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == (True, '') with app.test_request_context(): onetime_obj = FileOnetimeDownload.create( @@ -1594,58 +1628,177 @@ def test_validate_url_download(vldt_record, vldt_file, is_enabled, vldt_token, match = re.search(r'[?&]token=([^&]+)', create_download_url(onetime_obj)) onetime_token = match.group(1) db.session.flush() - assert validate_url_download('', '', onetime_token, False) == (True, '') + assert validate_url_download( + matching_record, matching_filename, onetime_token, False) == (True, '') with patch('weko_records_ui.utils.validate_token', return_value=False): - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'The provided token is invalid.') with patch('weko_records_ui.utils.is_secret_url_feature_enabled', return_value=False): - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'This feature is currently disabled.') with patch('weko_records_ui.utils.validate_file_access', return_value=False): - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'This file is currently not available for this feature.') with patch('weko_records_ui.utils.validate_download_record', return_value=False): - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'This file is currently not available for this feature.') + # record_id/file_name mismatch: Reject + assert validate_url_download( + {'recid': 999}, matching_filename, secret_token, True) == ( + False, 'This file is currently not available for this feature.') + + # record_id match, file_name mismatch: not a real file on the item: Reject + assert validate_url_download( + matching_record, 'nonexistent.txt', secret_token, True) == ( + False, 'This file is currently not available for this feature.') + + # record_id match, file_name mismatch: a different, legitimately + # existing file on the *same* item: Reject + assert validate_url_download( + matching_record, 'other_legit_file.txt', secret_token, True) == ( + False, 'This file is currently not available for this feature.') + + # record_id mismatch, file_name mismatch: Reject + assert validate_url_download( + {'recid': 999}, 'other.txt', secret_token, True) == ( + False, 'This file is currently not available for this feature.') + + # Same four mismatch cases as above (record_id only / file_name only + # with a nonexistent name / file_name only with a different real + # file / both), repeated for the onetime-URL path with onetime_token, + # to confirm the match check applies identically to both URL types. + assert validate_url_download( + {'recid': 999}, matching_filename, onetime_token, False) == ( + False, 'This file is currently not available for this feature.') + assert validate_url_download( + matching_record, 'nonexistent.txt', onetime_token, False) == ( + False, 'This file is currently not available for this feature.') + assert validate_url_download( + matching_record, 'other_legit_file.txt', onetime_token, False) == ( + False, 'This file is currently not available for this feature.') + assert validate_url_download( + {'recid': 999}, 'other.txt', onetime_token, False) == ( + False, 'This file is currently not available for this feature.') + secret_obj.is_deleted = True db.session.commit() - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'This URL has been deactivated.') secret_obj.is_deleted = False secret_obj.download_count = 10 db.session.commit() - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'The download limit has been exceeded.') secret_obj.download_count = 0 db.session.commit() with patch('weko_records_ui.utils.dt') as mock_dt: mock_dt.now.return_value = dt.now(timezone.utc) + timedelta(days=31) - assert validate_url_download('', '', secret_token, True) == ( + assert validate_url_download( + matching_record, matching_filename, secret_token, True) == ( False, 'The expiration date for download has been exceeded.') onetime_obj.is_deleted = True db.session.commit() - assert validate_url_download('', '', onetime_token, False) == ( + assert validate_url_download( + matching_record, matching_filename, onetime_token, False) == ( False, 'This URL has been deactivated.') onetime_obj.is_deleted = False onetime_obj.download_count = 10 db.session.commit() - assert validate_url_download('', '', onetime_token, False) == ( + assert validate_url_download( + matching_record, matching_filename, onetime_token, False) == ( False, 'The download limit has been exceeded.') onetime_obj.download_count = 0 db.session.commit() with patch('weko_records_ui.utils.dt') as mock_dt: mock_dt.now.return_value = dt.now(timezone.utc) + timedelta(days=31) - assert validate_url_download('', '', onetime_token, False) == ( + assert validate_url_download( + matching_record, matching_filename, onetime_token, False) == ( False, 'The expiration date for download has been exceeded.') +# def ensure_url_record_matches(url_obj, record_id, file_name): +# .tox/c1/bin/pytest --cov=weko_records_ui tests/test_utils.py::test_ensure_url_record_matches -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp +def test_ensure_url_record_matches(): + + # Build real FileSecretDownload instances. + def make_secret(record_id, file_name): + return FileSecretDownload( + creator_id=1, record_id=record_id, file_name=file_name, + label_name='test', expiration_date=dt.now(timezone.utc), + download_limit=1) + + # Build real FileOnetimeDownload instances. + def make_onetime(record_id, file_name): + return FileOnetimeDownload( + approver_id=1, record_id=record_id, file_name=file_name, + expiration_date=dt.now(timezone.utc), download_limit=1, + user_mail='test@example.org', is_guest=False, extra_info={}) + + # Decision table. + url_obj = make_secret(record_id='1', file_name='test.txt') + # rule 1: record_id match, file_name match -> allow (True) + assert ensure_url_record_matches(url_obj, '1', 'test.txt') is True + # rule 2: record_id match, file_name mismatch -> reject (False) + assert ensure_url_record_matches(url_obj, '1', 'other.txt') is False + # rule 3: record_id mismatch, file_name match -> reject (False) + assert ensure_url_record_matches(url_obj, '2', 'test.txt') is False + # rule 4: record_id mismatch, file_name mismatch -> reject (False) + assert ensure_url_record_matches(url_obj, '2', 'other.txt') is False + + # Both accepted url_obj types must be recognized. + onetime_obj = make_onetime(record_id='1', file_name='test.txt') + assert ensure_url_record_matches(onetime_obj, '1', 'test.txt') is True + + # url_obj is None: rejected without raising. + assert ensure_url_record_matches(None, '1', 'test.txt') is False + + # url_obj is of a type other than FileSecretDownload/FileOnetimeDownload. + class UnexpectedType: + def __init__(self, record_id, file_name): + self.record_id = record_id + self.file_name = file_name + assert ensure_url_record_matches( + UnexpectedType(record_id='1', file_name='test.txt'), + '1', 'test.txt') is False + + # Boundary/abnormal inputs must not raise, and must be rejected when + # they do not match a non-None url_obj. + assert ensure_url_record_matches(url_obj, None, 'test.txt') is False + assert ensure_url_record_matches(url_obj, '1', None) is False + assert ensure_url_record_matches(url_obj, '', 'test.txt') is False + + # url_obj.record_id and record_id have different types: compared + # after str() conversion, so equal values should still match. + int_id_obj = make_secret(record_id=1, file_name='test.txt') + assert ensure_url_record_matches(int_id_obj, '1', 'test.txt') is True + assert ensure_url_record_matches(int_id_obj, 1, 'test.txt') is True + assert ensure_url_record_matches(int_id_obj, '2', 'test.txt') is False + + # file_name containing path traversal / script-injection-like + # characters must not raise, and must be rejected unless it is an + # exact match. + malicious_names = ['../../etc/passwd', '', + "' OR '1'='1", '--', 'a' * 5000] + for name in malicious_names: + assert ensure_url_record_matches(url_obj, '1', name) is False + # An exact match (even of an unusual file name) is still allowed. + exact_obj = make_secret(record_id='1', file_name=name) + assert ensure_url_record_matches(exact_obj, '1', name) is True + + # .tox/c1/bin/pytest --cov=weko_records_ui tests/test_utils.py::test_validate_file_access -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp def test_validate_file_access(): with patch('weko_records_ui.utils.is_secret_file', return_value=True): diff --git a/modules/weko-records-ui/tests/test_views.py b/modules/weko-records-ui/tests/test_views.py index c428874d7d..668ce3293d 100644 --- a/modules/weko-records-ui/tests/test_views.py +++ b/modules/weko-records-ui/tests/test_views.py @@ -894,21 +894,47 @@ def test_copy_secret_url(app, client, records): assert res.json['url'] == expected_secret_url with patch('weko_records_ui.views.can_manage_secret_url', return_value=False): - with pytest.raises(Exception): - res = client.get(url) - assert res.status_code == 403 - with patch('weko_records_ui.views.create_download_url', + # abort(403) must propagate as an actual 403 response. + res = client.get(url) + assert res.status_code == 403 + with patch('weko_records_ui.views.can_manage_secret_url', + return_value=True), \ + patch('weko_records_ui.views.create_download_url', side_effect=Exception('Test Error')): + # can_manage_secret_url must stay True here, otherwise the real + # permission check would reject with 403 before ever reaching + # create_download_url(), and this would not test a genuine 500. res = client.get(url) assert res.status_code == 500 with patch('weko_records_ui.views.can_manage_secret_url', return_value=True): + # secret_url_id does not exist url = url_for('invenio_records_ui.recid_copy_secret_url', pid_value=records[1]['recid'].pid_value, filename=records[1]['filename'], secret_url_id=99) # invalid secret_url_id - res = client.get(url) - assert res.json['url'] is None + res_not_exist = client.get(url) + assert res_not_exist.status_code == 404 + + # secret_url_id exists, but belongs to a *different* item. + # Its file_name is deliberately set to match the *requested* filename. + other_secret_obj = FileSecretDownload.create( + creator_id=1, + record_id=records[0]['recid'].pid_value, + file_name=records[1]['filename'], + label_name='other item link', + expiration_date=datetime.now(timezone.utc) + timedelta(days=1), + download_limit=1, + ) + mismatched_url = url_for( + 'invenio_records_ui.recid_copy_secret_url', + pid_value=records[1]['recid'].pid_value, + filename=records[1]['filename'], + secret_url_id=other_secret_obj.id) + res_mismatch = client.get(mismatched_url) + assert res_mismatch.status_code == 404 + # The mismatch/not exist response must be indistinguishable to the caller. + assert res_mismatch.get_data() == res_not_exist.get_data() # .tox/c1/bin/pytest --cov=weko_records_ui tests/test_views.py::test_copy_onetime_url -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp @@ -942,21 +968,49 @@ def test_copy_onetime_url(app, client, records): assert res.json['url'] == expected_onetime_url with patch('weko_records_ui.views.can_manage_onetime_url', return_value=False): - with pytest.raises(Exception): - res = client.get(url) - assert res.status_code == 403 - with patch('weko_records_ui.views.create_download_url', + # abort(403) must propagate as an actual 403 response + res = client.get(url) + assert res.status_code == 403 + with patch('weko_records_ui.views.can_manage_onetime_url', + return_value=True), \ + patch('weko_records_ui.views.create_download_url', side_effect=Exception('Test Error')): + # can_manage_onetime_url must stay True here, otherwise the real + # permission check would reject with 403 before ever reaching + # create_download_url(), and this would not test a genuine 500. res = client.get(url) assert res.status_code == 500 with patch('weko_records_ui.views.can_manage_onetime_url', return_value=True): + # onetime_url_id does not exist url = url_for('invenio_records_ui.recid_copy_onetime_url', pid_value=records[1]['recid'].pid_value, filename=records[1]['filename'], onetime_url_id=99) # invalid onetime_url_id - res = client.get(url) - assert res.json['url'] is None + res_not_exist = client.get(url) + assert res_not_exist.status_code == 404 + + # onetime_url_id exists, but belongs to a *different* item. + # Its file_name is deliberately set to match the *requested* filename. + other_onetime_obj = FileOnetimeDownload.create( + approver_id=1, + record_id=records[0]['recid'].pid_value, + file_name=records[1]['filename'], + expiration_date=datetime.now(timezone.utc) + timedelta(days=1), + download_limit=1, + user_mail='test@example.org', + is_guest=False, + extra_info={} + ) + mismatched_url = url_for( + 'invenio_records_ui.recid_copy_onetime_url', + pid_value=records[1]['recid'].pid_value, + filename=records[1]['filename'], + onetime_url_id=other_onetime_obj.id) + res_mismatch = client.get(mismatched_url) + assert res_mismatch.status_code == 404 + # The mismatch/not exist response must be indistinguishable to the caller. + assert res_mismatch.get_data() == res_not_exist.get_data() # .tox/c1/bin/pytest --cov=weko_records_ui tests/test_views.py::test_delete_secret_url -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp @@ -984,11 +1038,16 @@ def test_delete_secret_url(client, records): assert secret_obj.is_deleted == True with patch('weko_records_ui.views.can_manage_secret_url', return_value=False): - with pytest.raises(Exception): - res = client.delete(url) - assert res.status_code == 403 - with patch('weko_records_ui.models.FileSecretDownload.delete_logically', + # abort(403) must propagate as an actual 403 response. + res = client.delete(url) + assert res.status_code == 403 + with patch('weko_records_ui.views.can_manage_secret_url', + return_value=True), \ + patch('weko_records_ui.models.FileSecretDownload.delete_logically', side_effect=Exception('Test Error')): + # can_manage_secret_url must stay True here, otherwise the real + # permission check would reject with 403 before ever reaching + # delete_logically(), and this would not test a genuine 500. res = client.delete(url) assert res.status_code == 500 with patch('weko_records_ui.views.can_manage_secret_url', @@ -997,9 +1056,32 @@ def test_delete_secret_url(client, records): pid_value=records[1]['recid'].pid_value, filename=records[1]['filename'], secret_url_id=99) # invalid secret_url_id - with pytest.raises(Exception): - res = client.delete(url) - assert res.status_code == 404 + # abort(404) must propagate as an actual 404 response, not be + # swallowed into a 500. + res_not_exist = client.delete(url) + assert res_not_exist.status_code == 404 + + # secret_url_id exists, but belongs to a *different* item. + # Its file_name is deliberately set to match the *requested* filename. + other_secret_obj = FileSecretDownload.create( + creator_id=1, + record_id=records[0]['recid'].pid_value, + file_name=records[1]['filename'], + label_name='other item link', + expiration_date=datetime.now(timezone.utc) + timedelta(days=1), + download_limit=1, + ) + mismatched_url = url_for( + 'invenio_records_ui.recid_delete_secret_url', + pid_value=records[1]['recid'].pid_value, + filename=records[1]['filename'], + secret_url_id=other_secret_obj.id) + res_mismatch = client.delete(mismatched_url) + assert res_mismatch.status_code == 404 + # The mismatch/not exist response must be indistinguishable to the caller. + assert res_mismatch.get_data() == res_not_exist.get_data() + # The other item's secret URL must remain untouched. + assert other_secret_obj.is_deleted == False # .tox/c1/bin/pytest --cov=weko_records_ui tests/test_views.py::test_delete_onetime_url -vv -s --cov-branch --cov-report=term --basetemp=/code/modules/weko-records-ui/.tox/c1/tmp @@ -1029,11 +1111,17 @@ def test_delete_onetime_url(client, records): assert onetime_obj.is_deleted == True with patch('weko_records_ui.views.can_manage_onetime_url', return_value=False): - with pytest.raises(Exception): - res = client.delete(url) - assert res.status_code == 403 - with patch('weko_records_ui.models.FileOnetimeDownload.delete_logically', + # abort(403) must propagate as an actual 403 response. + res = client.delete(url) + assert res.status_code == 403 + with patch('weko_records_ui.views.can_manage_onetime_url', + return_value=True), \ + patch('weko_records_ui.models.FileOnetimeDownload.delete_logically', side_effect=Exception('Test Error')): + # can_manage_onetime_url must stay True here, otherwise the + # real permission check would reject with 403 before ever + # reaching delete_logically(), and this would not test a + # genuine 500. res = client.delete(url) assert res.status_code == 500 with patch('weko_records_ui.views.can_manage_onetime_url', @@ -1042,9 +1130,34 @@ def test_delete_onetime_url(client, records): pid_value=records[1]['recid'].pid_value, filename=records[1]['filename'], onetime_url_id=99) - with pytest.raises(Exception): - res = client.delete(url) - assert res.status_code == 404 + # abort(404) must propagate as an actual 404 response, not be + # swallowed into a 500. + res_not_exist = client.delete(url) + assert res_not_exist.status_code == 404 + + # onetime_url_id exists, but belongs to a *different* item. + # Its file_name is deliberately set to match the *requested* filename. + other_onetime_obj = FileOnetimeDownload.create( + approver_id=1, + record_id=records[0]['recid'].pid_value, + file_name=records[1]['filename'], + expiration_date=datetime.now(timezone.utc) + timedelta(days=1), + download_limit=1, + user_mail='test@example.org', + is_guest=False, + extra_info={} + ) + mismatched_url = url_for( + 'invenio_records_ui.recid_delete_onetime_url', + pid_value=records[1]['recid'].pid_value, + filename=records[1]['filename'], + onetime_url_id=other_onetime_obj.id) + res_mismatch = client.delete(mismatched_url) + assert res_mismatch.status_code == 404 + # The mismatch/not exist response must be indistinguishable to the caller. + assert res_mismatch.get_data() == res_not_exist.get_data() + # The other item's onetime URL must remain untouched. + assert other_onetime_obj.is_deleted == False # def default_view_method(pid, record, filename=None, template=None, **kwargs): diff --git a/modules/weko-records-ui/weko_records_ui/utils.py b/modules/weko-records-ui/weko_records_ui/utils.py index f00489bf1a..90d409d315 100644 --- a/modules/weko-records-ui/weko_records_ui/utils.py +++ b/modules/weko-records-ui/weko_records_ui/utils.py @@ -1338,23 +1338,31 @@ def validate_onetime_download_token( def is_private_index(record): - """Check index of workflow is private. + """Check index of the record is private. - :param record:Record data. - :return: + Args: + record (dict): Record data. + Returns: + bool: + True if all indexes the item belongs to are non-public, + False if at least one index is public. + Note: + - An item that belongs to no index at all is treated as private. + - An index is only treated as public if its own public_state is + True and its public_date (if set) is today or in the past, AND + every ancestor index above it in the tree satisfies the same + condition. If any ancestor index is non-public (or has a + public_date in the future), the index is treated as non-public + as well, regardless of the index's own public_state. + - If the item belongs to at least one such public index, it is not + private. """ from weko_index_tree.api import Indexes list_index = record.get("path") - indexes = Indexes.get_path_list(list_index) - publish_state = 6 - for index in indexes: - if len(indexes) == 1: - if not index[publish_state]: - return True - else: - if index[publish_state]: - return False - return False + if not list_index: + return True + # Delegate the public/private determination to the Indexes API. + return not Indexes.is_public_state_and_not_in_future(list_index) def validate_download_record(record): @@ -2322,6 +2330,32 @@ def convert_token_into_obj(token, is_secret_url): return url_obj +def ensure_url_record_matches(url_obj, record_id, file_name): + """Check that the issued URL record matches the requested target. + + Args: + url_obj: The download URL record fetched from the database. + record_id: The record (item) ID actually being requested. + file_name: The file name actually being requested. + + Returns: + bool: True if 'url_obj' was issued for the given + 'record_id'/'file_name', False otherwise (including when the + values do not match, or are None/empty). + """ + # Ensure that the URL object is valid and of the correct type before proceeding. + if ( + url_obj is None or + type(url_obj) not in (FileSecretDownload, FileOnetimeDownload) + ): + return False + + return ( + str(url_obj.record_id) == str(record_id) + and url_obj.file_name == file_name + ) + + def validate_url_download(record, filename, token, is_secret_url=None): """Validate the request for URL download. @@ -2354,6 +2388,12 @@ def validate_url_download(record, filename, token, is_secret_url=None): # Check if the URL is still valid url_obj = convert_token_into_obj(token, is_secret_url) + + # Check that the token was actually issued for the requested item/file. + # The same generic message as the file-access check above is used. + if not ensure_url_record_matches(url_obj, record.get('recid'), filename): + return False, _('This file is currently not available for this feature.') + if url_obj.is_deleted is True: return False, _('This URL has been deactivated.') if url_obj.download_count >= url_obj.download_limit: diff --git a/modules/weko-records-ui/weko_records_ui/views.py b/modules/weko-records-ui/weko_records_ui/views.py index e118b35043..6292101a64 100644 --- a/modules/weko-records-ui/weko_records_ui/views.py +++ b/modules/weko-records-ui/weko_records_ui/views.py @@ -37,6 +37,7 @@ from flask_login import login_required from flask_security import current_user from sqlalchemy.orm.exc import NoResultFound +from werkzeug.exceptions import HTTPException from invenio_db import db from invenio_files_rest.models import ObjectVersion, FileInstance from invenio_files_rest.permissions import has_update_version_role @@ -95,6 +96,7 @@ from weko_records_ui.utils import ( check_items_settings, can_manage_onetime_url, can_manage_secret_url, create_download_url, create_secret_url_record, delete_version, + ensure_url_record_matches, export_preprocess, get_billing_file_download_permission, get_file_info_list, get_google_detaset_meta, get_google_scholar_meta, get_groups_price, get_min_price_billing_file_download, get_record_permalink, hide_by_email, @@ -985,13 +987,23 @@ def copy_secret_url(pid, record, **kwargs): Raises: flask.abort: - 403 if the user does not have enough permissions. + - 404 if the URL does not exist or does not belong to the requested pid/filename. - 500 if an error occurs while preparing the URL. """ try: if not can_manage_secret_url(record, kwargs['filename']): abort(403) url_record = FileSecretDownload.get_by_id(kwargs['secret_url_id']) + # Reject (as 404) when the secret_url_id does not exist, + # or when it exists but does not match the requested pid/filename. + if not url_record or not ensure_url_record_matches( + url_record, pid.pid_value, kwargs['filename']): + abort(404) url = create_download_url(url_record) + except HTTPException: + # Let abort()'s intended status code (403/404) propagate as-is, + # so we simply re-raise the HTTPException. + raise except Exception as e: current_app.logger.error(e) abort(500) @@ -1018,13 +1030,23 @@ def copy_onetime_url(pid, record, **kwargs): Raises: flask.abort: - 403 if the user does not have enough permissions. + - 404 if the URL does not exist or does not belong to the requested pid/filename. - 500 if an error occurs while preparing the URL. """ try: if not can_manage_onetime_url(record, kwargs['filename']): abort(403) url_record = FileOnetimeDownload.get_by_id(kwargs['onetime_url_id']) + # Reject (as 404) when the onetime_url_id does not exist, + # or when it exists but does not actually belong to the requested pid/filename. + if not url_record or not ensure_url_record_matches( + url_record, pid.pid_value, kwargs['filename']): + abort(404) url = create_download_url(url_record) + except HTTPException: + # Let abort()'s intended status code (403/404) propagate as-is, + # so we simply re-raise the HTTPException. + raise except Exception as e: current_app.logger.error(e) abort(500) @@ -1051,15 +1073,23 @@ def delete_secret_url(pid, record, **kwargs): Raises: flask.abort: - 403 if the user does not have enough permissions. + - 404 if the URL does not exist or does not belong to the requested pid/filename. - 500 if an error occurs while deleting the URL. """ try: if not can_manage_secret_url(record, kwargs['filename']): abort(403) url_record = FileSecretDownload.get_by_id(kwargs['secret_url_id']) - if not url_record: + # Reject (as 404) when the secret_url_id does not exist, + # or when it exists but does not actually belong to the requested pid/filename. + if not url_record or not ensure_url_record_matches( + url_record, pid.pid_value, kwargs['filename']): abort(404) url_record.delete_logically() + except HTTPException: + # Let abort()'s intended status code (403/404) propagate as-is, + # so we simply re-raise the HTTPException. + raise except Exception as e: current_app.logger.error(e) abort(500) @@ -1086,15 +1116,23 @@ def delete_onetime_url(pid, record, **kwargs): Raises: flask.abort: - 403 if the user does not have enough permissions. + - 404 if the URL does not exist or does not belong to the requested pid/filename. - 500 if an error occurs while deleting the URL. """ try: if not can_manage_onetime_url(record, kwargs['filename']): abort(403) url_record = FileOnetimeDownload.get_by_id(kwargs['onetime_url_id']) - if not url_record: + # Reject (as 404) when the onetime_url_id does not exist, + # or when it exists but does not actually belong to the requested pid/filename. + if not url_record or not ensure_url_record_matches( + url_record, pid.pid_value, kwargs['filename']): abort(404) url_record.delete_logically() + except HTTPException: + # Let abort()'s intended status code (403/404) propagate as-is, + # so we simply re-raise the HTTPException. + raise except Exception as e: current_app.logger.error(e) abort(500) diff --git a/nginx/Dockerfile b/nginx/Dockerfile index b125547a09..218aff84cb 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -47,7 +47,8 @@ RUN apt-get update && \ supervisor \ shibboleth-sp-common \ shibboleth-sp-utils \ - php-fpm php-curl + fcgiwrap \ + python3-requests WORKDIR /tmp # dpkg-buildpackage names the .deb after the build host architecture @@ -58,11 +59,13 @@ RUN dpkg -i nginx_1.20.1-1~focal_*.deb ADD supervisord.conf /etc/supervisor/supervisord.conf +# supervisord.conf points shibauthorizer / shibresponder at the x86_64 +# library directory. Rewrite it for the build architecture (e.g. aarch64). +RUN sed -i "s#/usr/lib/x86_64-linux-gnu/shibboleth/#/usr/lib/$(uname -m)-linux-gnu/shibboleth/#g" \ + /etc/supervisor/supervisord.conf ADD shibboleth2.xml /etc/shibboleth/shibboleth2.xml ADD attribute-map.xml /etc/shibboleth/attribute-map.xml ADD attribute-policy.xml /etc/shibboleth/attribute-policy.xml -RUN sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/php-fpm.conf && \ - sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/pool.d/www.conf ADD ./keys/server.crt /etc/shibboleth/server.crt ADD ./keys/server.key /etc/shibboleth/server.key @@ -82,9 +85,8 @@ ADD redirect_list.map /etc/nginx/redirect_list.map RUN chmod 400 /etc/nginx/server.key RUN mkdir /usr/share/nginx/html/secure -#ADD ./phpinfo.php /usr/share/nginx/html/secure/phpinfo.php -#ADD ./index.php /usr/share/nginx/html/secure/index.php -ADD ./login.php /usr/share/nginx/html/secure/login.php +ADD ./login.py /usr/share/nginx/html/secure/login.py +RUN chmod 755 /usr/share/nginx/html/secure/login.py ADD ./shib_clear_headers /etc/nginx/shib_clear_headers ADD ./shib_fastcgi_params /etc/nginx/shib_fastcgi_params diff --git a/nginx/Dockerfile.ams b/nginx/Dockerfile.ams index 4aedca1ae5..b11d12ad2e 100644 --- a/nginx/Dockerfile.ams +++ b/nginx/Dockerfile.ams @@ -8,8 +8,6 @@ RUN apt-get update -y && \ RUN echo "deb http://nginx.org/packages/ubuntu focal nginx" | tee /etc/apt/sources.list.d/nginx.list RUN echo "deb-src http://nginx.org/packages/ubuntu focal nginx" | tee -a /etc/apt/sources.list.d/nginx.list RUN curl -fsSL https://nginx.org/keys/nginx_signing.key | apt-key add - -#RUN apt-get source -y nginx=1.18.0 -#RUN apt-get build-dep -y nginx=1.18.0 RUN apt-get update -y && \ apt-get source -y nginx=1.20.1 && \ apt-get build-dep -y nginx=1.20.1 @@ -19,42 +17,37 @@ RUN wget "https://github.com/samizdatco/nginx-http-auth-digest/archive/master.zi # https://github.com/nginx-shib/nginx-http-shibboleth RUN wget "https://github.com/nginx-shib/nginx-http-shibboleth/archive/v2.0.1.tar.gz" -O nginx-http-shibboleth-2.0.1.tar.gz RUN wget "https://github.com/openresty/headers-more-nginx-module/archive/v0.33.tar.gz" -O headers-more-nginx-module-0.33.tar.gz -RUN wget "https://github.com/apache/incubator-pagespeed-ngx/archive/v1.13.35.2-stable.tar.gz" -O incubator-pagespeed-ngx-1.13.35.2-stable.tar.gz RUN wget "https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz" -O ngx_cache_purge-2.3.tar.gz RUN unzip nginx-http-auth-digest.zip && \ tar zxf nginx-http-shibboleth-2.0.1.tar.gz && \ tar zxf headers-more-nginx-module-0.33.tar.gz && \ - tar zxvf incubator-pagespeed-ngx-1.13.35.2-stable.tar.gz && \ tar zxf ngx_cache_purge-2.3.tar.gz -RUN cd /tmp/incubator-pagespeed-ngx-1.13.35.2-stable ; wget https://dl.google.com/dl/page-speed/psol/1.13.35.2-x64.tar.gz ; tar -xzvf 1.13.35.2-x64.tar.gz -#RUN sed -i "s#--modules-path=/usr/lib/nginx/modules#--modules-path=/usr/lib/nginx/modules --add-module=/tmp/headers-more-nginx-module-0.33 --add-module=/tmp/nginx-http-shibboleth-2.0.1 --add-module=/tmp/nginx-http-auth-digest-master --add-module=/tmp/incubator-pagespeed-ngx-1.13.35.2-stable --add-module=/tmp/ngx_cache_purge-2.3 #g" nginx-1.18.0/debian/rules -#RUN cd nginx-1.18.0 && dpkg-buildpackage -b -RUN sed -i "s#--modules-path=/usr/lib/nginx/modules#--modules-path=/usr/lib/nginx/modules --add-module=/tmp/headers-more-nginx-module-0.33 --add-module=/tmp/nginx-http-shibboleth-2.0.1 --add-module=/tmp/nginx-http-auth-digest-master --add-module=/tmp/incubator-pagespeed-ngx-1.13.35.2-stable --add-module=/tmp/ngx_cache_purge-2.3 #g" nginx-1.20.1/debian/rules +RUN sed -i "s#--modules-path=/usr/lib/nginx/modules#--modules-path=/usr/lib/nginx/modules --add-module=/tmp/headers-more-nginx-module-0.33 --add-module=/tmp/nginx-http-shibboleth-2.0.1 --add-module=/tmp/nginx-http-auth-digest-master --add-module=/tmp/ngx_cache_purge-2.3 #g" nginx-1.20.1/debian/rules RUN cd nginx-1.20.1 && dpkg-buildpackage -b FROM ubuntu:focal AS nginx-stage_1 ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y openssl wget curl unzip supervisor shibboleth-sp-common shibboleth-sp-utils php-fpm php-curl fcgiwrap python3-pip -RUN pip3 install requests +RUN apt-get update && apt-get install -y openssl wget curl unzip supervisor shibboleth-sp-common shibboleth-sp-utils fcgiwrap python3-requests WORKDIR /tmp -#COPY --from=nginx-with-shib /tmp/nginx_1.18.0-2~focal_amd64.deb . -#COPY --from=nginx-with-shib /tmp/nginx-dbg_1.18.0-2~focal_amd64.deb . -#RUN dpkg -i nginx_1.18.0-2~focal_amd64.deb -COPY --from=nginx-with-shib /tmp/nginx_1.20.1-1~focal_amd64.deb . -COPY --from=nginx-with-shib /tmp/nginx-dbg_1.20.1-1~focal_amd64.deb . -RUN dpkg -i nginx_1.20.1-1~focal_amd64.deb +# dpkg-buildpackage names the .deb after the build host architecture +# (amd64 / arm64), so match it with a wildcard instead of hard-coding it. +COPY --from=nginx-with-shib /tmp/nginx_1.20.1-1~focal_*.deb ./ +COPY --from=nginx-with-shib /tmp/nginx-dbg_1.20.1-1~focal_*.deb ./ +RUN dpkg -i nginx_1.20.1-1~focal_*.deb ADD supervisord.conf /etc/supervisor/supervisord.conf +# supervisord.conf points shibauthorizer / shibresponder at the x86_64 +# library directory. Rewrite it for the build architecture (e.g. aarch64). +RUN sed -i "s#/usr/lib/x86_64-linux-gnu/shibboleth/#/usr/lib/$(uname -m)-linux-gnu/shibboleth/#g" \ + /etc/supervisor/supervisord.conf ADD shibboleth2.xml /etc/shibboleth/shibboleth2.xml ADD attribute-map.xml /etc/shibboleth/attribute-map.xml ADD attribute-policy.xml /etc/shibboleth/attribute-policy.xml -RUN sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/php-fpm.conf -RUN sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/pool.d/www.conf ADD ./keys/server.crt /etc/shibboleth/server.crt ADD ./keys/server.key /etc/shibboleth/server.key @@ -75,8 +68,6 @@ ADD redirect_list.map /etc/nginx/redirect_list.map RUN chmod 400 /etc/nginx/server.key RUN mkdir /usr/share/nginx/html/secure -#ADD ./phpinfo.php /usr/share/nginx/html/secure/phpinfo.php -#ADD ./index.php /usr/share/nginx/html/secure/index.php ADD ./login.py /usr/share/nginx/html/secure/login.py RUN chmod 755 /usr/share/nginx/html/secure/login.py diff --git a/nginx/Dockerfile.arm64 b/nginx/Dockerfile.arm64 index b125547a09..218aff84cb 100644 --- a/nginx/Dockerfile.arm64 +++ b/nginx/Dockerfile.arm64 @@ -47,7 +47,8 @@ RUN apt-get update && \ supervisor \ shibboleth-sp-common \ shibboleth-sp-utils \ - php-fpm php-curl + fcgiwrap \ + python3-requests WORKDIR /tmp # dpkg-buildpackage names the .deb after the build host architecture @@ -58,11 +59,13 @@ RUN dpkg -i nginx_1.20.1-1~focal_*.deb ADD supervisord.conf /etc/supervisor/supervisord.conf +# supervisord.conf points shibauthorizer / shibresponder at the x86_64 +# library directory. Rewrite it for the build architecture (e.g. aarch64). +RUN sed -i "s#/usr/lib/x86_64-linux-gnu/shibboleth/#/usr/lib/$(uname -m)-linux-gnu/shibboleth/#g" \ + /etc/supervisor/supervisord.conf ADD shibboleth2.xml /etc/shibboleth/shibboleth2.xml ADD attribute-map.xml /etc/shibboleth/attribute-map.xml ADD attribute-policy.xml /etc/shibboleth/attribute-policy.xml -RUN sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/php-fpm.conf && \ - sed -i 's/\/run\/php/\/tmp/g' /etc/php/7.4/fpm/pool.d/www.conf ADD ./keys/server.crt /etc/shibboleth/server.crt ADD ./keys/server.key /etc/shibboleth/server.key @@ -82,9 +85,8 @@ ADD redirect_list.map /etc/nginx/redirect_list.map RUN chmod 400 /etc/nginx/server.key RUN mkdir /usr/share/nginx/html/secure -#ADD ./phpinfo.php /usr/share/nginx/html/secure/phpinfo.php -#ADD ./index.php /usr/share/nginx/html/secure/index.php -ADD ./login.php /usr/share/nginx/html/secure/login.php +ADD ./login.py /usr/share/nginx/html/secure/login.py +RUN chmod 755 /usr/share/nginx/html/secure/login.py ADD ./shib_clear_headers /etc/nginx/shib_clear_headers ADD ./shib_fastcgi_params /etc/nginx/shib_fastcgi_params diff --git a/nginx/index.php b/nginx/index.php deleted file mode 100644 index 1d4a3a952b..0000000000 --- a/nginx/index.php +++ /dev/null @@ -1,388 +0,0 @@ - - - - - - 属性受信の確認ページ - - - - - -
- -
- 属性受信の確認ページ
-あなたのIdPは、<" . htmlspecialchars($_SERVER['Shib-Identity-Provider']) . ">です。"; -?> -
-
- - - - - - - - - - - - - - - // of shib.conf. - // - // 3. shibd and httpd restart - // - $checkScopedAttribute = false; - //$checkScopedAttribute = true; - - function get_exportAssertion(){ - $eadata = ""; - $xml = simplexml_load_string(file_get_contents($_SERVER['Shib-Assertion-01'])); - foreach ( $xml->children("urn:oasis:names:tc:SAML:2.0:assertion")->AttributeStatement->Attribute as $attr) { - // eduPersonPrincipalName (ePPN) - if ((string)$attr->attributes()->Name == 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6') { - $eadata["eppn"] = $attr->AttributeValue; - } - - // eduPersonScopedAffiliation (ePSA) - if ((string)$attr->attributes()->Name == 'urn:oid:1.3.6.1.4.1.5923.1.1.1.9') { - $affiliation_array = array(); - foreach ($attr->AttributeValue as $val) { - // Add a backslash to match the behavior of SP. - // example: "member;staff" --> "member\;staff" - $val = str_replace(';', '\\;', $val); - array_push($affiliation_array, $val); - } - $eadata["affiliation"] = (string)join(";", $affiliation_array); - } - - // eduPersonAffiliation (ePA) - if ((string)$attr->attributes()->Name == 'urn:oid:1.3.6.1.4.1.5923.1.1.1.1') { - $affiliation_array = array(); - foreach ($attr->AttributeValue as $val) { - // Add a backslash to match the behavior of SP. - // example: "member;staff@example.ac.jp" --> "member\;staff@example.ac.jp" - $val = str_replace(';', '\\;', $val); - array_push($affiliation_array, $val); - } - $eadata["unscoped-affiliation"] = (string)join(";", $affiliation_array); - } - - // gakuninScopedPersonalUniqueCode - if ((string)$attr->attributes()->Name == 'urn:oid:1.3.6.1.4.1.32264.1.1.6') { - $affiliation_array = array(); - foreach ($attr->AttributeValue as $val) { - // Add a backslash to match the behavior of SP. - // example: "faculty;staff:12345@example.ac.jp" --> "faculty\;staff:12345@example.ac.jp" - $val = str_replace(';', '\\;', $val); - array_push($affiliation_array, $val); - } - $eadata["gakuninScopedPersonalUniqueCode"] = (string)join(";", $affiliation_array); - } - - // eduPersonUniqueId - if ((string)$attr->attributes()->Name == 'urn:oid:1.3.6.1.4.1.5923.1.1.1.13') { - $eadata["eduPersonUniqueId"] = $attr->AttributeValue; - } - } - return $eadata; - } - - function normal_value($attr_value = ''){ - } - - function notice_value($attr_value = ''){ - if (strpos($attr_value, '\;') !== FALSE) - print '

注意:属性値にセミコロンが含まれているためSPによっては正しく動作しない可能性があります

'; - } - - function warning_value($attr_value = ''){ - if (strpos($attr_value, '\;') !== FALSE) - print '

警告:属性値にセミコロンが含まれているため正しくありません

'; - } - - function check_exportAssertion($attr, $attr_value = '', $ea_attr_value = ''){ - // scoped attributes (e.g. ePPN, ePSA) - $scoped_attrs = array( - "eppn", - "affiliation", - "gakuninScopedPersonalUniqueCode", - "eduPersonUniqueId", - "eduPersonScopedAffiliation", - ); - - // affiliation attributes (i.e. ePA, ePSA) - $affiliation_attrs = array( - "unscoped-affiliation", - "affiliation", - "eduPersonAffiliation", - "eduPersonScopedAffiliation", - ); - - // eduPersonAffiliation permissible values - // (eduPerson Object Class Specification (200806)) - $epaary = array( - "faculty", "student", "staff", "alum", "member", - "affiliate", "employee", "library-walk-in", - ); - - // Check of scope for scoped attributes (e.g. ePPN, ePSA) - if (in_array($attr, $scoped_attrs, true)) { - if (strcmp($attr_value, $ea_attr_value)) { - print '

警告:メタデータで定義されているスコープと送出された属性のスコープが一致していないか、利用できる属性値ではありません。
'; - print '(送出された属性値は' . $ea_attr_value . 'でした。)

'; - } - } - - // Check of vocabulary for affiliation attributes - if (in_array($attr, $affiliation_attrs, true)) { - $ea_attr_value_ary = preg_split("/(?警告:' . $val . "は利用できる属性値ではありません。

"; - } - } - - } - } - - $envary = array( - "eppn" => array("ePPN(eduPersonPrincipalName)" , "normal_value"), - "persistent-id" => array("eduPersonTargetedID" , "notice_value"), - "o" => array("o(organizationName)" , "normal_value"), - "jao" => array("jao(jaOrganizationName)[日本語]" , "normal_value"), - "ou" => array("ou(organizationalUnitName)" , "normal_value"), - "jaou" => array("jaou(jaOrganizationalUnitName)[日本語]" , "normal_value"), - "unscoped-affiliation" => array("職位(eduPersonAffiliation)" , "warning_value"), - "affiliation" => array("スコープ付き職位(eduPersonScopedAffiliation)" , "warning_value"), - "entitlement" => array("権限(eduPersonEntitlement)" , "notice_value"), - "mail" => array("メールアドレス(mail)" , "normal_value"), - "givenName" => array("名(givenName)" , "normal_value"), - "jaGivenName" => array("名(jaGivenName)[日本語]" , "normal_value"), - "sn" => array("姓(sn)" , "normal_value"), - "jasn" => array("姓(jasn)[日本語]" , "normal_value"), - "displayName" => array("表示名(displayName)" , "normal_value"), - "jaDisplayName" => array("表示名(jaDisplayName)[日本語]" , "normal_value"), - "gakuninScopedPersonalUniqueCode" - => array("gakuninScopedPersonalUniqueCode" , "notice_value"), - "isMemberOf" => array("isMemberOf" , "notice_value"), - "assurance" => array("eduPersonAssurance" , "notice_value"), - "eduPersonUniqueId" => array("eduPersonUniqueId" , "normal_value"), - "eduPersonOrcid" => array("eduPersonOrcid" , "notice_value"), - ); - - $chart_classes = array( - array("key" => "chart-key_even", "val" => "chart-value_even"), - array("key" => "chart-key_odd", "val" => "chart-value_odd" ), - ); - - $chart_class_notreceived = array( - "key" => "chart-key_notreceived", - "val" => "chart-value_notreceived"); - - if ($checkScopedAttribute === TRUE){ - $eadata=get_exportAssertion(); - } - - $i = 0; - foreach ($envary as $attr => $key) { - list($attr_description, $print_message) = $key; - - if ($i != 0) { - print "\n"; - } - - $chart_class = $chart_classes[$i % 2]; - - if (isset($_SERVER[$attr]) === FALSE) { - $chart_class = $chart_class_notreceived; - $val = "NOT RECEIVED"; - } else { - $val = htmlspecialchars($_SERVER[$attr], ENT_QUOTES, "UTF-8"); - } - - print ' '; - print ''; - print ''; - - $i = $i + 1; - } -?> - -
属性属性値
' . $attr_description . '' . $val; - print $print_message($_SERVER[$attr]); - - if ($checkScopedAttribute === TRUE && empty($eadata[$attr]) === FALSE){ - check_exportAssertion($attr, $_SERVER[$attr], $eadata[$attr]); - } - print '
-

現在のセッション情報の詳細はこちらへ。⇒セッション情報

-

このSPに対してログアウトする場合はこちらへ。⇒ログアウト
- (IdPに対してはログインした状態のままになりますのでご注意ください。
- IdPからもログアウトするためにはブラウザを閉じてください)

- - 0) { - print " \n"; - while (list($key, $value) = each($_SERVER)) { - print " \n"; - } - print "
$key" . htmlspecialchars($value, ENT_QUOTES, "UTF-8") . "
\n"; - } -?> - - - diff --git a/nginx/login.php b/nginx/login.php deleted file mode 100644 index 3aec5844a1..0000000000 --- a/nginx/login.php +++ /dev/null @@ -1,59 +0,0 @@ - - window.alert('Permission is invalid'); - window.location.href='".$base."';"; - //header("HTTP/1.1 403 Forbidden"); - //header("Location: ".$base); -}else{ - if(isset($_REQUEST['next'])){ - $next=$_REQUEST['next']; - }else{ - $next='%2F'; - } - // Post to the loopback address. WEKO accepts the attributes only from the - // addresses in WEKO_ACCOUNTS_SHIB_SP_ALLOWED_ADDRS, and nginx allows the - // POST to /weko/shib/login only from the loopback address. - $url = $_SERVER['REQUEST_SCHEME']."://127.0.0.1/weko/shib/login?next=".$next; - $curl = curl_init(); - $post_args=[]; - $post_args['SHIB_ATTR_USER_NAME']=$_SERVER['HTTP_WEKOID']; - $post_args["SHIB_ATTR_EPPN"]=$_SERVER['Remote-User']; - $post_args["SHIB_ATTR_MAIL"]=$_SERVER['mail']; - $post_args["SHIB_ATTR_SESSION_ID"]=$_SERVER['Shib-Session-ID']; - $post_args["SHIB_ATTR_ROLE_AUTHORITY_NAME"]=$_SERVER['HTTP_WEKOSOCIETYAFFILIATION']; - $options = array( - //Method - CURLOPT_POST => true,//POST - //body - CURLOPT_POSTFIELDS => http_build_query($post_args), - ); - $cookie=tempnam(sys_get_temp_dir(),'cookie_'); - //set options - curl_setopt($curl,CURLOPT_URL,$url); - curl_setopt($curl, CURLOPT_HTTPHEADER, array('Host: '.$_SERVER['SERVER_NAME'])); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_setopt($curl, CURLOPT_COOKIESESSION, true); - curl_setopt_array($curl, $options); - curl_setopt($curl,CURLOPT_COOKIEJAR,$cookie); - curl_setopt($curl,CURLOPT_COOKIEFILE,$cookie); - // request - $result = curl_exec($curl); - $info = curl_getinfo($curl); - $errno = curl_errno($curl); - $error = curl_error($curl); - curl_close($curl); - if (CURLE_OK !== $errno) { - throw new RuntimeException($error, $errno); - } - header("HTTP/1.1 302 Found"); - header("Location: ".$base.$result); - //var_dump($app_cookies[0]['value']); -} -?> diff --git a/nginx/phpinfo.php b/nginx/phpinfo.php deleted file mode 100644 index c9f5eeb129..0000000000 --- a/nginx/phpinfo.php +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/nginx/supervisord.conf b/nginx/supervisord.conf index b343023a3b..04073b7973 100644 --- a/nginx/supervisord.conf +++ b/nginx/supervisord.conf @@ -32,16 +32,6 @@ socket_mode=0777 redirect_stderr=true priority=2 -[program:php-fpm] -command =/usr/sbin/php-fpm7.4 -F -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stdout_logfile_maxbytes=0 -stderr_logfile=/dev/stderr -stderr_logfile_maxbytes=0 -socket_mode=0777 - [fcgi-program:fcgiwrap] command=/usr/sbin/fcgiwrap -f socket=unix:///usr/lib/systemd/system/fcgiwrap.socket diff --git a/nginx/weko-ams-restricted.conf b/nginx/weko-ams-restricted.conf index 13fd43cf82..2563555971 100644 --- a/nginx/weko-ams-restricted.conf +++ b/nginx/weko-ams-restricted.conf @@ -119,24 +119,6 @@ server { alias /usr/share/shibboleth/; } - #A secured location.(Extension: .php) - location ~ /secure/(.*\.php)$ { - shib_request /shibauthorizer; - shib_request_use_headers on; - include shib_fastcgi_params; - include shib_clear_headers; - - more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; - - fastcgi_pass unix:/tmp/php7.4-fpm.sock; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include fastcgi_params; - root /usr/share/nginx/html; - - fastcgi_param NO_CHECK_WEKOSOCIETYAFFILIATION TRUE; - } - #A secured location.(Extension: .py) location ~ /secure/(.*\.py)$ { shib_request /shibauthorizer; @@ -147,7 +129,6 @@ server { more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; fastcgi_pass unix:/usr/lib/systemd/system/fcgiwrap.socket; - # fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; root /usr/share/nginx/html; @@ -172,7 +153,7 @@ server { # } # The attributes of the Shibboleth SP are posted only by the login script - # on this server (secure/login.py, login.php), over the loopback address. + # on this server (secure/login.py), over the loopback address. # The address is the one of the connection, before real_ip rewrites it with # X-Forwarded-For, so that a trusted proxy address cannot be used to pose # as the loopback address. WEKO checks the same address diff --git a/nginx/weko-ams.conf b/nginx/weko-ams.conf index c1ed4916da..f2790e9141 100644 --- a/nginx/weko-ams.conf +++ b/nginx/weko-ams.conf @@ -139,24 +139,6 @@ server { alias /usr/share/shibboleth/; } - #A secured location.(Extension: .php) - location ~ /secure/(.*\.php)$ { - shib_request /shibauthorizer; - shib_request_use_headers on; - include shib_fastcgi_params; - include shib_clear_headers; - - more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; - - fastcgi_pass unix:/tmp/php7.4-fpm.sock; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include fastcgi_params; - root /usr/share/nginx/html; - - fastcgi_param NO_CHECK_WEKOSOCIETYAFFILIATION TRUE; - } - #A secured location.(Extension: .py) location ~ /secure/(.*\.py)$ { shib_request /shibauthorizer; @@ -167,7 +149,6 @@ server { more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; fastcgi_pass unix:/usr/lib/systemd/system/fcgiwrap.socket; - # fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; root /usr/share/nginx/html; @@ -192,7 +173,7 @@ server { # } # The attributes of the Shibboleth SP are posted only by the login script - # on this server (secure/login.py, login.php), over the loopback address. + # on this server (secure/login.py), over the loopback address. # The address is the one of the connection, before real_ip rewrites it with # X-Forwarded-For, so that a trusted proxy address cannot be used to pose # as the loopback address. WEKO checks the same address diff --git a/nginx/weko.conf b/nginx/weko.conf index a681be8ddc..58dd2f6fe5 100644 --- a/nginx/weko.conf +++ b/nginx/weko.conf @@ -110,24 +110,6 @@ server { alias /usr/share/shibboleth/; } - # #A secured location.(Extension: .php) - # location ~ /secure/(.*\.php)$ { - # shib_request /shibauthorizer; - # shib_request_use_headers on; - # include shib_fastcgi_params; - # include shib_clear_headers; - - # more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; - - # fastcgi_pass unix:/tmp/php7.4-fpm.sock; - # fastcgi_index index.php; - # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - # include fastcgi_params; - # root /usr/share/nginx/html; - - # fastcgi_param NO_CHECK_WEKOSOCIETYAFFILIATION TRUE; - # } - # #A secured location.(Extension: .py) # location ~ /secure/(.*\.py)$ { # shib_request /shibauthorizer; @@ -138,7 +120,6 @@ server { # more_clear_input_headers 'EPPN' 'DisplayName' 'Email' 'Persistent-Id'; # fastcgi_pass unix:/usr/lib/systemd/system/fcgiwrap.socket; - # # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # include fastcgi_params; # root /usr/share/nginx/html; @@ -207,7 +188,7 @@ server { # } # The attributes of the Shibboleth SP are posted only by the login script - # on this server (secure/login.py, login.php), over the loopback address. + # on this server (secure/login.py), over the loopback address. # The address is the one of the connection, before real_ip rewrites it with # X-Forwarded-For, so that a trusted proxy address cannot be used to pose # as the loopback address. WEKO checks the same address