Felles webgrensesnitt for mindre Postgres-baser driftet av Universitetsbiblioteket i Oslo som Letras (norske oversettelser av spansk og spanskamerikansk litteratur), Norsk Litteraturkrtikk (Beyer-basen)og Dommers populærnavn.
Innhold:
Requirements:
- PHP 7.1 and Composer
- NodeJS 18
- Docker and docker-compose
The app can also be run locally without Docker, but then you need to install Apache (or another web server) and Postgres.
npm install
to install frontend dependencies into./node_modules
npm run build
to build frontend components (CSS, JS)composer install
to install PHP dependencies into./vendor
docker-compose up
to start the app.
Docker Compose starts two containers: db
(the Postgres database) and app
(Apache + PHP).
When the app
container starts, it will first run the entrypoint.sh
script
which takes care of migrating the database,
creating all neccessary tables, collations etc.
Once ready, the app will be available at http://localhost:8080
To stop the server, press Ctrl-C.
The ub-baser:create-local-user
artisan command is used to create a local admin user in development,
where SAML is not configured. Please don't use this in production!
Without Docker: (requires local Postgres)
php artisan ub-baser:create-local-admin
With Docker:
docker-compose run --rm app php artisan ub-baser:create-local-admin
The source for this command is app/Console/Commands/CreateAdminCommand.php
A random password will be shown. There is no way to retrieve it if you loose it, so please make a note of it in a secure storage (password manager or similar).
You should now be able to login at http://localhost:8080/login and add additional rights at http://localhost:8080/admin/users/1/edit
Data can be imported from the initial-import
folder using the import commands. For instance you
can import data from initial-import/litteraturkritikk
to the litteraturkritikk
database like so:
Without Docker: (requires local Postgres install)
php artisan import:litteraturkritikk initial-import/litteraturkritikk
With Docker:
docker-compose run --rm -v "$(pwd)"/initial-import:/initial-import app php artisan import:litteraturkritikk /initial-import/litteraturkritikk
The source for this command is app/Console/Commands/ImportLitteraturkritikkCommand.php
.
If the app container fails to start, try rebuilding the image:
docker-compose build
To clean up and start from scratch:
docker-compose down
docker system prune
docker volume prune # Note: Deletes the local database
If you need to delete the database and start over again, use the migrate:fresh
artisan command:
docker-compose run --rm app php artisan migrate:fresh
If you need to rebuild the Docker image, e.g. after having made changes to the Dockerfile, run:
docker-compose up --build
You don't need to rebuild the image after changes to the application itself, since the current directory is mounted into the Docker container when using the development configuration (see docker-compose.yml).
When testing changes to the Apache config, it can be useful to also mount the config file/folder,
to avoid having to rebuild the image for every change. Here's an example where we mount
the sites-available
folder:
docker-compose run --rm -v "$(pwd)"/docker/sites-available:/etc/apache2/sites-available/ app
Tests will run in the staging
environment by default,
so that tests will run isolated from your development environment.
To start containers for this environment:
APP_ENV=staging docker-compose up -d
Run the WebdriverIO tests against http://localhost:8080:
npm run test
To run tests against another host, you can specify TEST_BASE_URL
.
If you use Docker Machine:
TEST_BASE_URL="http://$(docker-machine ip):8081" npm run test
To run a single test:
APP_ENV=staging npx wdio tests/wdio.conf.js --spec ./tests/selenium/specs/login.js
Run npm run watch
to build these resources as you make changes to the source files in the resources
folder.
Install Apache and PHP 8.1:
dnf install httpd mod_ssl
dnf module install php:8.1/common
Follow the steps in Product Documentation for Red Hat Enterprise Linux 9. Chapter 6. Using the PHP scripting language to make Apache start at boot.
Install packages needed by PHP and NPM dependencies:
dnf install autoconf automake libtool make cmake gettext zlib-devel
Install the Postgres client library and PHP module:
dnf install postgresql php-pdo php-pgsql
Install the GD and Zip PHP modules and their dependencies:
dnf install gd gd-devel php-gd php-zip
Git is needed to clone the app:
dnf install git
Node 18 is needed to build frontend components, but is not a runtime dependency:
dnf module install nodejs:18/common composer
Composer is needed for installing PHP dependencies:
Follow the steps Kokebok for bestilling og utstedelse av SSL-sertifikater to order a certificate and install it with Apache.
Store the certificate in /etc/httpd/uio-ssl/2024/ub-baser_uio_no.crt
,
the private key in /etc/httpd/uio-ssl/2024/ub-baser.uio.no.key
and
the CA certificate in /etc/httpd/uio-ssl/2024/intermediate.crt
.
The files should be owned by root.
Run restorecon -r /etc/httpd/
after copying the files to restore SELinux security contexts,
ensuring that Apache has read access to the files.
Clone the app and install Composer and NPM dependencies:
cd /srv
git clone https://github.com/uio-library/ub-baser
cd ub-baser
composer install
npm install
npm run production
For Apache to get access to /srv/ub-baser/
, we must assign the httpd_sys_content_t
SELinux security context.
And httpd_sys_rw_content_t
to the folder that should be writable.
semanage fcontext -a -t httpd_sys_content_t /srv/ub-baser/
semanage fcontext -a -t httpd_sys_rw_content_t /srv/ub-baser/storage
restorecon -R -v /srv/ub-baser/
Ref: Setting up the Apache HTTP web server and httpd_selinux
- Add your database settings to the
/srv/ub-baser/.env
file. - In production, make sure to set
APP_DEBUG=false
to avoid leaking secrets.
This will both test that we can connect to the database and add/update any missing tables:
php artisan migrate
Create a SAML tenant uio-weblogin
for the UiO Weblogin IdP (the name "uio-weblogin" should match
the value for SAML2_DEFAULT_TENANT
in the .env
file), using metadata from
https://weblogin.uio.no/simplesaml/saml2/idp/metadata.php?output=xhtml.
php artisan saml2:create-tenant \
--key=uio-weblogin \
--entityId=https://weblogin.uio.no/simplesaml/saml2/idp/metadata.php \
--loginUrl=https://weblogin.uio.no/simplesaml/saml2/idp/SSOService.php \
--logoutUrl=https://weblogin.uio.no/simplesaml/saml2/idp/SingleLogoutService.php \
--x509cert="MIIFGDCCBACgAwIBAgICA0YwDQYJKoZIhvcNAQEEBQAwga0xCzAJBgNVBAYTAk5PMQ0wCwYDVQQHEwRPc2xvMRswGQYDVQQKExJVbml2ZXJzaXR5IG9mIE9zbG8xOjA4BgNVBAsTMUNlbnRlciBmb3IgSW5mb3JtYXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlcyAoVVNJVCkxEDAOBgNVBAMTB1VTSVQgQ0ExJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB1c2l0LnVpby5ubzAeFw0xMzExMTUwOTU2NTZaFw0zMzExMTAwOTU2NTZaMIGmMQswCQYDVQQGEwJOTzEbMBkGA1UEChMSVW5pdmVyc2l0eSBvZiBPc2xvMTowOAYDVQQLEzFDZW50ZXIgZm9yIEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMgKFVTSVQpMRgwFgYDVQQDEw93ZWJsb2dpbi51aW8ubm8xJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB1c2l0LnVpby5ubzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALbX2nZYBbUO5tdeG3lVaF/1kdcf1HrGfE/IITNyMqogHT6VPbQxzL5mN1IcHZPDi6Wi+Lg8V9RcXvgP7X6ajUk0PTPmqwil/izS3fUtyKnyulZn/M3+JUW9BHIazhpAsifbqkp5YHt+bFQ/FlStb8ZVzVRIHJZ+GmLKPV+DJ1MsnPyC1InSsdMHEBpt6tYPk3n5qZ7gU3CqI/b/rGP8ECGszRuf8RiL2zO5tlg9mgQ4I+xryIRVf963b538xq+OzGTbIr6eo4+5DolNDsEStOYfAQhnKaZ7QV6PEzS0lcMIXj5L6vZ4aGXEbESB5r/iWUX0HF8qpuMKzw6OgPddEOkCAwEAAaOCAUUwggFBMAkGA1UdEwQCMAAwOAYJYIZIAYb4QgENBCsWKVczQ0Etc2lnbmVkIE9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSCTt0rB5AtfBv0H+svAC8CtdlQHzCB2gYDVR0jBIHSMIHPgBQvUjhkJlXqclR0W+ZyPM/xsI3mB6GBs6SBsDCBrTELMAkGA1UEBhMCTk8xDTALBgNVBAcTBE9zbG8xGzAZBgNVBAoTElVuaXZlcnNpdHkgb2YgT3NsbzE6MDgGA1UECxMxQ2VudGVyIGZvciBJbmZvcm1hdGlvbiBUZWNobm9sb2d5IFNlcnZpY2VzIChVU0lUKTEQMA4GA1UEAxMHVVNJVCBDQTEkMCIGCSqGSIb3DQEJARYVd2VibWFzdGVyQHVzaXQudWlvLm5vggEAMA0GCSqGSIb3DQEBBAUAA4IBAQA+0egBeRpeEC5aDJaJqgtDMMn1y9LmybNTjxKB6/7ICRt3Uhf3EII/oJeuAs99voK96OEu+IEffq4hXSjMnxbHrJWlfEvcIrF9kQfbJKZpXv7jCz8BoDDp4N8mUGeq7xEdWhQsH5+o5aj4WUPMeuZjTPnxNt/cGTJxh95v2Gm0JQ/XmwrUZ41xOxPPsfwQjGIqjWjIsDIvpSlFSqphH967uwWB84GLKHj3jvESUUIhz5Y0TBDcXpF1o0gD4RXBwJEES8cZlYk2pzpH2n6ZpUInfshq2MVCHCPkLN5Iykx+53WmUzeAzFRY4NkuSJxy+poRpbtygxvGateGiFEkm+dD"
See https://github.com/24Slides/laravel-saml2 for more options.
To list configured IdPs:
php artisan saml2:list-tenants
To use UiO's test environment instead, create a new tenant using metadata from https://weblogin-test.uio.no/simplesaml/saml2/idp/metadata.php?output=xhtml:
php artisan saml2:create-tenant \
--key=uio-weblogin-test \
--entityId=https://weblogin-test.uio.no/simplesaml \
--loginUrl=https://weblogin-test.uio.no/simplesaml/saml2/idp/SSOService.php \
--logoutUrl=https://weblogin-test.uio.no/simplesaml/saml2/idp/SingleLogoutService.php \
--x509cert="MIIFHTCCBAWgAwIBAgICA0UwDQYJKoZIhvcNAQEEBQAwga0xCzAJBgNVBAYTAk5PMQ0wCwYDVQQHEwRPc2xvMRswGQYDVQQKExJVbml2ZXJzaXR5IG9mIE9zbG8xOjA4BgNVBAsTMUNlbnRlciBmb3IgSW5mb3JtYXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlcyAoVVNJVCkxEDAOBgNVBAMTB1VTSVQgQ0ExJDAiBgkqhkiG9w0BCQEWFXdlYm1hc3RlckB1c2l0LnVpby5ubzAeFw0xMzEwMjgxMjUxMzlaFw0yMzEwMjYxMjUxMzlaMIGrMQswCQYDVQQGEwJOTzEbMBkGA1UEChMSVW5pdmVyc2l0eSBvZiBPc2xvMTowOAYDVQQLEzFDZW50ZXIgZm9yIEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMgKFVTSVQpMR0wGwYDVQQDExR3ZWJsb2dpbi10ZXN0LnVpby5ubzEkMCIGCSqGSIb3DQEJARYVd2VibWFzdGVyQHVzaXQudWlvLm5vMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArditxDo2pV0pKddtUo1yH7Znjwkf+PSYMMiI+W1EaSAQ3zyayNnF/xGCK0FmPIs0eZACs/0mODn9flhyINjWb224GS45Ry592u6Ta9HTyWrnPvAgYw0TMs/evc76B+XATiQcw4xNFFhqG1hPGYaNHwZaWmngG2F+B5xY5twN/lMwwuD+Q3sJ/B39pfHy+Y6jy0bEDpM2RrqF5tARKnU1iikwViHI0bWlFEAF2piuj/M4Cha5seIxEZhZtLLMfFX7Q7JTwprisL3pwtALNPSm9sZRLCcpFIFRNUzpgf3HNFvsYdyDw/1gXj/2RBzLBImDG1QQxg67tT/OQpL9gqO2CwIDAQABo4IBRTCCAUEwCQYDVR0TBAIwADA4BglghkgBhvhCAQ0EKxYpVzNDQS1zaWduZWQgT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNrZ2Qv6rFnLBBtjKZ9sm8eiWzc8MIHaBgNVHSMEgdIwgc+AFC9SOGQmVepyVHRb5nI8z/GwjeYHoYGzpIGwMIGtMQswCQYDVQQGEwJOTzENMAsGA1UEBxMET3NsbzEbMBkGA1UEChMSVW5pdmVyc2l0eSBvZiBPc2xvMTowOAYDVQQLEzFDZW50ZXIgZm9yIEluZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMgKFVTSVQpMRAwDgYDVQQDEwdVU0lUIENBMSQwIgYJKoZIhvcNAQkBFhV3ZWJtYXN0ZXJAdXNpdC51aW8ubm+CAQAwDQYJKoZIhvcNAQEEBQADggEBAFfb5ednPCcwA/U6/v4JIHEOREQlXcpcKsQHT9dNjKWSiXUxF1N3KlKRCrdOSe4DVS1BkmgnAUY1GSnT1acxvsBmW1m0qu6cFlr4K8qgkDio2nPQtIv608+e51Iop6JN1B9m1UX14DXxDjozH3bLO95mChhJ00jKdIFtAXOpjZJS8LC/ii/GjKrPUl8Yz9gcmxykkryr+HdZtBUpcLDCnPhkv5Qqkr0SZQBlsr2XzCydll4ZkYUYYLRG/wxlKop9PY3dKMXLf+jlNiVH9YbiRoa1NdxDsFKTpfhnzVNbGbNp4Gkrn4lut007fhMfcq1ZbATR39NzU84WkMjbhGaisNA="
and set SAML2_DEFAULT_TENANT=uio-weblogin-test
in the .env
file.
Add vhosts to /etc/apache2/sites-available/ub-baser.conf
:
<VirtualHost *:80>
# This first-listed virtual host is also the default for *:80
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
SSLEngine On
SSLCertificateFile /etc/httpd/uio-ssl/2024/ub-baser_uio_no.crt
SSLCertificateKeyFile /etc/httpd/uio-ssl/2024/ub-baser.uio.no.key
SSLCertificateChainFile /etc/httpd/uio-ssl/2024/intermediate.crt
SSLCipherSuite ALL:+HIGH:!ADH:!EXP:!SSLv2:!SSLv3:!MEDIUM:!LOW:!NULL:!aNULL
SSLProtocol all -TLSv1.1 -TLSv1 -SSLv2 -SSLv3
SSLHonorCipherOrder on
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
DocumentRoot /srv/ub-baser/public
DirectoryIndex index.php
RewriteEngine On
<Directory /srv/ub-baser/public>
Options FollowSymLinks
AllowOverride None
Require all granted
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L]
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName www.norsklitteraturkritikk.no
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/norsk-litteraturkritikk [R,L]
</VirtualHost>
<VirtualHost *:80>
ServerName norsklitteraturkritikk.no
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/norsk-litteraturkritikk [R,L]
</VirtualHost>
<VirtualHost *:80>
ServerName opes.uio.no
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/opes [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName www.norsklitteraturkritikk.no
Include /etc/apache2/include/ssl.conf
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/norsk-litteraturkritikk [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName norsklitteraturkritikk.no
Include /etc/apache2/include/ssl.conf
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/norsk-litteraturkritikk [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName opes.uio.no
Include /etc/apache2/include/ssl.conf
RewriteEngine On
RewriteRule (.*) https://ub-baser.uio.no/opes [R,L]
</VirtualHost>
-
In
.env
, make sure that the following settings are set:APP_ENV=production
APP_DEBUG=false
APP_KEY
is not empty (runphp artisan key:generate
to generate a key if none exists)
-
The webserver should only have write access to the
storage
directory:chown -R apache:ub-utv /srv/ub-baser/storage chmod -R u+rwX,g+rwX /srv/ub-baser/storage
-
Only use SAML, not local users, in production.
In production, it's a good idea to create caches manually:
php artisan config:cache # stored in bootstrap/cache/config.php
php artisan route:cache # stored in bootstrap/cache/routes.php
php artisan view:cache # stored in storage/framework/views
This way, we don't need to give the webserver write access to bootstrap/cache
.
When a new user logs in using SSO, a user with no rights is automatically added to the users
table.
An admin can then assign rights to the user.
To create the first admin user, use the ub-baser:create-saml-user
command:
php artisan ub-baser:create-saml-user username@uio.no --admin
The user is stored in the users
table with admin
rights and can now login using SSO.