# Queue

A queueing system to be used at labs at EWI (tudelft.nl).

## Contributing

Please read our [contribution guide](CONTRIBUTING.md).

## Requirements

- Java 17+

## Project setup

In order to have the project setup properly for development a few steps need to be taken.

1.	First the config file should be moved from the template into the actual properties file
	by executing `cp src/main/resources/application.yaml.template src/main/resources/application.yaml`
	from the root directory of the project. 
1.  For tests to work, `application-test.properties` file (which the GitLab pipeline copies from application-h2.properties) should be created in `src/test/resources`.
1.  Make sure to also have an `application.properties` file in `src/test/resources` with the content `spring.profiles.active=testing`.
1.  The `test-connection` setting in `application.yaml` is set to `false` by default for the development environment, but it is advised to set this to `true` for production deployment. 
1.	Follow these [instructions](https://gitlab.ewi.tudelft.nl/eip/labrador/queue/-/blob/master/CONTRIBUTING.md#submitting-your-changes)
		  to submit your work

### Run website from IDE

1. Install [IntelliJ IDEA Professional](https://www.jetbrains.com/idea/) ([free for students](https://www.jetbrains.com/student/))
1. [Import project from Gradle model](https://www.jetbrains.com/idea/help/importing-project-from-gradle-model.html)
1. For IntelliJ to run the project make sure are running jdk 8.
1. Start the project by right-clicking `QueueApplication` and clicking 'Run'
1. Visit http://localhost:8081/
1. Finally visit http://localhost:8081/login to login.
   Various test users credentials can be found in the `DataBaseLoader` class or in [Test Data](https://gitlab.ewi.tudelft.nl/groups/eip/labrador/-/wikis/test-data). 

### Run website from CLI

1. `gradle build`
1. `sudo java -jar build/libs/queue-0.0.1-SNAPSHOT.jar`
1. Visit http://localhost:8081/
1. Finally visit http://localhost:8081/login to login.
   Various test users credentials can be found in the `DataBaseLoader` class.

## Deployment

The `deploy/` directory contains an Ansible playbook that can be used to provision the machine. Specifically, it contains:

 - an nginx site config (`default`) with an upstream for tomcat on port 8080 together with config for a letsencrypt generated SSL certificate.
 - a SystemD configuration (`queue.service`) that runs the jar at `/var/www/queue/queue-0.0.1-SNAPSHOT.jar` as root on startup and logs to `/var/log/queue.log`.
 - an ansible config that installs Oracle java 8, nginx, postgres, haveged, the SystemD job, the jar, and starts the services.
 - an `application.yaml` file with application-specific configuration, such as the database settings.

To run the playbook, first replace the hostname and your SSH key in `deploy/hosts`, then run `./deploy/run.sh`.

Note that the current `application.yaml` contains `spring.jpa.hibernate.ddl-auto=create` which will drop and create the database upon reboot!

## Configuration

See `application.yaml`. Chrome does not yet fully support the Web Push API and uses GCM to handle sending and delivery of push messages. To use the GCM API you need a GCM API key. [This](https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web#make-a-project-on-the-google-developer-console) page explains how to obtain one.

You can place an `application.yaml` on the classpath which overrides the `application.yaml` in the jar itself.

> Nowadays, Chrome supports VAPID (Voluntary Application Identification) for Web Push API and it is no longer necessary to obtain an API key. The Web Push library should be updated to the latest version that I'm maintaining at https://github.com/MartijnDwars/web-push. For VAPID, we need to generate yet another keypair..

### Environments

The system distinguishes two profiles: `development` and `production`. Use the `application.yaml` file to set the active profile. The active profile has the following impact:

- The `DatabaseLoader`, which loads the database with dummy data, is only run if the `development` profile is active.
- The `error.html` page only shows stack traces if the `development` profile is active.

## Domain

- A `Request` is always initiated by a student. At some point, it will be handled by an assistant.

## Database migrations
The queue uses [liquibase](https://www.liquibase.org/index.html) for database migrations.
The changelog can be found in src/main/resources/changeLog.yaml, the corresponding documentation can be found 
[here](https://www.liquibase.org/documentation/index.html). To run and test a liquibase migration in the development
environment you need to change a few settings in the application properties file.

1. Point Spring to the changelog you want to apply using the: `liquibase.change-log=` property
1. Change the `spring.datasource.url=` property to a persistent h2 url rather than the in-memory variant.

## Roles

A user has a single _default_ role and a single _contextual_ role for every course that he participates in. This distinction is necessary because, for example, a teacher may not be a teacher in every course. The default roles are `STUDENT`,  `TEACHER`, and `ADMIN`. The contextual roles are `STUDENT`, `ASSISTANT`, `MANAGER` and `TEACHER`.

A user can have at most one contextual role within a course. An `ASSISTANT` is able to handle requests. A `MANAGER` can do everything an `ASSISTANT` can, but may also manage assignments and labs. A `TEACHER` can do everything an `ASSISTANT` can, but can also remove the course and change the course's name.

The default roles form a hierarchy. That is, an `ADMIN` can do everything a `TEACHER` can, and a `TEACHER` can do everything a `STUDENT` can. A user with default role `STUDENT` has no special permissions. A user with default role `TEACHER` is allowed to create courses. A user with default role `ADMIN` is allowed to change a user's default role.

When an `ADMIN` operates within a course, he acts as a `TEACHER`. It is adviced to use the admin account solely for administrative usages (such as setting up a course).

## Security

- Passwords are encrypted with bcrypt, which protects against rainbow table attacks and remains resistant to brute-force attacks when computing power increases.
- All forms are accomodated with an `_csrf` field to protect against CSRF attacks.
- We only support HTTPS connections, because supporting both HTTP and HTTPS is too much of an effort (and there is little to no reason to support HTTP). Spring Security will make sure the HTTP Strict Transport Security (HSTS) headers are set. In development mode, make sure you accept the certificate. On OS X, adding `keystore.p12` to Keychain will get you a green padlock in Chrome. This is required for push notifications, among others.
- All `User`s have a `Role`, which is one of: STUDENT, ASSISTANT, TEACHER, ADMIN.

## SSO

SAML provides Single Sign On (SSO). The Queue system acts as a Service Provider (SP). It requests and obtains an identity assertion from the identity provider (TUDelft gatekeeper). By default, only identity assertions with a max age of 7200 seconds are trusted. This can be changed by updating `maxAuthenticationAge` on the `WebSSOProfileImpl` object. Alternatively, you can force the IDP to re-authenticate the user by setting `forceAuthN` to `true` on the `WebSSOProfileOptions` object.

In development you may not want to go through the SAML process. The traditional login page is still available at `/login`. This requires that a `User` with a username and password exists.

### Crypto

The SAML messages are cryptographically signed. The file `security/samlKeystore.jks` is a Java keystore. It has no password (when prompted for a password, enter the empty string). The development keystore contains a key with alias `apollo` and password `nalle123`. For production, you'll want to:

1. Create a PKCS12 file using your private key and a CA signed certificate of it. You can use openssl command for this: `openssl pkcs12 -export -in /etc/ssl/certs/queue_ewi_tudelft_nl.crt -inkey /etc/ssl/private/queue.ewi.tudelft.nl.key -certfile /etc/ssl/certs/queue_ewi_tudelft_nl.crt -out testkeystore.p12`
1. Create a Java keystore (.jks file) using the `keytool`: `keytool -importkeystore -srckeystore testkeystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS`
1. To list the keys in the Java keystore: `keytool -list -v -keystore keystore.jks`

([source](http://xacmlinfo.org/2014/06/13/how-to-keystore-creating-jks-file-from-existing-private-key-and-certificate/))

### Metadata

The SP metadata can be generated automatically. To do so, visit `/saml/metadata`. The browser will provide a file `spring_saml_metadata.xml`. You need to deliver this file to the TU Delft.

## Push

Notifications are sent using the [Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API). The Push API is [experimental](http://caniuse.com/#feat=push-api) and we expect things to break. Note that the Push API requires HTTPS.

## Apache2 config
With regards to deployment and the high number of students, ensure that the value for MaxRequestWorkers in Apache2 is high enough. 
For example, for about 450 first year students, the number 250 was found to be suitable.
The file to edit for this is mpm_prefork.conf and the directive is MaxRequestWorkers.


## Notes to developers

### Security

- To ensure forms have a `_csrf` field, either make sure the form uses `th:action`, as this automagically adds the field or add it by hand as a hidden input field.

### Faster Authentication
- When logging in on the development build, you can speed up the process by leaving out "@tudelft.nl" and the password and it will automatically fill in the credentials for you.