Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update documentation for the auth consolidation #956

Merged
merged 5 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/actions/acceptance-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ runs:
echo "Set timeouts: ${{ inputs.timeouts }}"
shell: bash

- name: Append hosts file to enable "pass.local" on localhost
shell: bash
run: echo "127.0.0.1 pass.local" | sudo tee -a /etc/hosts

- name: Checkout pass-docker
uses: actions/checkout@v3
with:
Expand Down
84 changes: 33 additions & 51 deletions docs/dev/authentication-authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,61 @@

### User Interface Authentication

Authentication for the user interface occurs through the use of an authentication service provider (SP), [pass-auth](https://github.com/eclipse-pass/pass-auth), written as a node application employing the express framework and acting as a reverse proxy in front of pass-core and other api services.
Authentication for the user interface occurs through the use of an authentication service provider (SP), [pass-core](https://github.com/eclipse-pass/pass-core).

`pass-auth` is configured to initiate a SAML exchange with a known identity provider (IDP) that supports [Shibboleth](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/overview). Although `pass-auth` itself is not a Shibboleth service provider specifically, it is a generalized SAML service provider that can handle specific Shibboleth interactions with an IDP. In response to a valid `authn` assertion against an IDP, `pass-auth` expects to receive and validate a Shibboleth SAML assertion against its assertion consumer service (ACS) URL. This assertion is expected to contain the following Shibboleth attributes:
`pass-core` is configured to initiate a SAML exchange with a known identity provider (IDP) that supports [Shibboleth](https://shibboleth.atlassian.net/wiki/spaces/CONCEPT/overview). Although `pass-core` itself is not a Shibboleth service provider specifically, it is a generalized SAML service provider that can handle specific Shibboleth interactions with an IDP. In response to a valid `authn` assertion against an IDP, `pass-core` expects to receive and validate a Shibboleth SAML assertion against its assertion consumer service (ACS) URL. This assertion is expected to contain the following Shibboleth attributes:

```
'urn:oid:2.16.840.1.113730.3.1.241': 'displayName'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.9': 'scopedAffiliation'
'urn:oid:0.9.2342.19200300.100.1.3': 'email'
'urn:oid:2.16.840.1.113730.3.1.3': 'employeeNumber'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.1': 'employeeIdType'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.6': 'eppn'
'urn:oid:2.5.4.42': 'givenName'
'urn:oid:2.5.4.4': 'surname'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.13': 'uniqueId'
'urn:oid:0.9.2342.19200300.100.1.1': 'uniqueIdType'
'urn:oid:2.16.840.1.113730.3.1.241': 'Display name'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.9': 'Scoped affiliation'
'urn:oid:0.9.2342.19200300.100.1.3': 'Email'
'urn:oid:2.16.840.1.113730.3.1.3': 'Employee id'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.6': 'eduPersonPrincipalName'
'urn:oid:2.5.4.42': 'Given name'
'urn:oid:2.5.4.4': 'Surname'
'urn:oid:1.3.6.1.4.1.5923.1.1.1.13': 'Unique id'
```

These Shibboleth attributes are used to locate a user in `pass-core` and set up a user object on the session. Initially, `pass-auth` will use these attributes to build shibboleth headers that allow the user service in `pass-core` to locate a user. Additionally, on all subsequent requests to `pass-core`, `pass-auth` will add the following headers using the Shibboleth attributes stored on a session:

```
'Displayname'
'Mail'
'Eppn'
'Givenname'
'Sn'
'Affiliation'
'Employeenumber'
'unique-id'
'employeeid'
```

These headers are required by `pass-core` to authenticate and authorize requests to its API.

`pass-auth`, establishes a server side session and delivers a http-only cookie to the browser client which [`pass-ui`](https://github.com/eclipse-pass/pass-ui/) will use to establish a client side session in the user interface. This http-only cookie is delivered back to `pass-auth` by the user interface with every request which `pass-auth` will validate before it forwards on a request with the required Shibboleth headers to `pass-core`.
These Shibboleth attributes are used to locate a user in `pass-core` and set up a user object on the session. `pass-core`, establishes a server side session and delivers a http-only cookie to the browser client which [`pass-ui`](https://github.com/eclipse-pass/pass-ui/) will use to establish a client side session in the user interface. This http-only cookie is delivered back to `pass-core` by the user interface with every request.

This series of interactions is depicted as follows:

![pass auth interactions diagram](https://user-images.githubusercontent.com/6305935/234353077-519a6987-96bc-44df-80e1-ee06920bcb40.png)
![authentication interactions diagram](pass_authn.png)

### REST API Authentication

Every request to the [REST API](https://github.com/eclipse-pass/pass-core) must be authenticated. If it is not authenticated, it is denied.

Requests to the API come from two types of clients, backend services and users. Requests from users must have already been authenticated with Shibboleth and have the headers specified above. If a request contains Shibboleth headers, it is considered trusted, authentication succeeds, it is associated with a user, and given the SUBMITTER role. If the user does not exist, it is created. If the user does exist, it is updated to reflect the information in the headers. If the request does not contain the Shibboleth headers, it undergoes HTTP basic authentication. There is one HTTP basic user defined with the BACKEND role for the backend services.

Mapping from Shibboleth headers to PASS users:
* displayName: Displayname header
* email: Mail header
* firstName: Givenname header
* lastName: Sn header
* username: Eppn header
* affiliations: DOMAIN, all values after splitting affiliation header on `;`
Mapping from Shibboleth attributes to PASS users:
* displayName: Display name
* email: Email
* firstName: Given name
* lastName: Surname
* username: Eppn
* affiliations: DOMAIN, all values after splitting affiliation on `;`
* locatorIds: UNIQUE ID, INSTITUTIONAL_ID, EMPLOYEE_ID
* role: SUBMITTER

The DOMAIN is the value of the Eppn header after `@`.
The UNIQUE_ID is `DOMAIN:unique-id:` joined to the value of the unique id header before `@`.
The INSTITUTIONAL_ID is `DOMAIN:eppn` joined to the value of the Eppn header before the `@`.
The EMOLOYEE_ID is `DOMAIN:employeeid` joined to the value of the Employeenumber header.
The DOMAIN is the value of the Eppn attribute after `@`.
The UNIQUE_ID is `DOMAIN:unique-id:` joined to the value of the unique id attribute before `@`.
The INSTITUTIONAL_ID is `DOMAIN:eppn` joined to the value of the Eppn attribute before the `@`.
The EMOLOYEE_ID is `DOMAIN:employeeid` joined to the value of the Employe id value.

The locatorIds are used to find an existing user in the system. If any of the locatorIds match an existing user, the user is considered to match.

### Example mapping

Request headers:
Shibboleth attributes:
* Eppn: [email protected]
* Displayname: Sally M. Submitter
* Display name: Sally M. Submitter
* Mail: [email protected]
* Givenname: Sally
* Sn: Submitter
* Given name: Sally
* Surnamen: Submitter
* Affiliation: [email protected]
* Employeenumber: 02342342
* unique-id: [email protected]
* Employee id: 02342342
* Unique id: [email protected]

Resulting User:
* affiliation: [email protected], johnshopkins.edu
Expand All @@ -98,10 +80,10 @@ Object permissions:

| Type | Create | Read | Update | Delete |
| ------- | ------- | ---- | ------- | ------- |
| Submission | BACKEND or SUBMITTER | any | BACKEND or owns submission | BACKEND |
| SubmissionEvent | BACKEND or owns submission | any | BACKEND or owns submission | BACKEND |
| File | BACKEND or owns submission | any | BACKEND or owns submission | BACKEND |
| Publication | BACKEND or SUBMITTER | any | BACKEND or SUBMITTER | BACKEND |
| Submission | BACKEND or SUBMITTER | any | BACKEND or owns submission | BACKEND or owns submission|
| SubmissionEvent | BACKEND or owns submission | any | BACKEND | BACKEND |
| File | BACKEND or owns submission | any | BACKEND or owns submission | BACKEND or owns submission|
| Publication | BACKEND or owns submission | any | BACKEND or owns submission | BACKEND or owns submission|
| * | BACKEND | any | BACKEND | BACKEND |

The permissions are all role based with the exception of "owns submission". By "owns submission" what is meant is that the user is the submitter or a preparer on a submission associated with the object. A submitter is the target of the submitter relationship on a Submission. A preparer is the target of the preparers relationship on a Submission. SubmissionEvent and File are associated with a submission through a submission relationship. The intent is to make sure submitters can only modify submissions which they have created or are explicitly allowed to help on.
103 changes: 11 additions & 92 deletions docs/dev/local_demo.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
# Setting Up a Local Demo System

## Configure pass.local

You will need edit your local hosts file with

```bash
127.0.0.1 pass.local
```

Instructions to edit the `/etc/hosts` file are avaiable for

* [Windows hosts file](https://www.freecodecamp.org/news/how-to-find-and-edit-a-windows-hosts-file/)
* [Mac/Linux hosts file](https://setapp.com/how-to/edit-mac-hosts-file)

## Install Docker

The demo application runs on [Docker](https://www.docker.com) and [Docker Compose](https://docs.docker.com/compose/).
Expand Down Expand Up @@ -41,67 +28,21 @@ cd pass-docker

From here you can `git fetch` the latest code and `git checkout <new branch>` to switch between code branches.

There is a helper script [demo.sh](https://github.com/eclipse-pass/pass-docker/blob/main/demo.sh)
that wraps up the `docker-compose` command with the appropriate configuration files, and
you can run any [docker compose cli command](https://docs.docker.com/compose/reference/).


## Pull Latest Docker Images

This will pull all the latest pass docker images.

```bash
./demo.sh pull
```
Look at the [pass-docker](https://github.com/eclipse-pass/pass-docker/) documentation for how to use the
`docker-compose` command to start PASS. You can run any [docker compose cli command](https://docs.docker.com/compose/reference/).

## Start Pass

This will start pass in the background

```bash
./demo.sh up -d
```

At this point you will need to watch the logs to wait until the
`pass-core` shows that it has started. This is something we
are actively working to address.
Pull Docker images and start PASS in the background:

```bash
./demo.sh logs -f
```

It might take a while, but once the logs _stop_ with the message below
then it is ready to load the base data.

```
[main] [Pass, ] INFO org.eclipse.pass.main.Main.logStarted - Started Main in 69.863 seconds (JVM running for 79.59)
```

That base data can now be loaded using the following command.

```bash
./demo.sh up loader
```

If run successfully it should exit with a message like

```bash
loader | ### ./data/submissions.json
loader | Reading file ./data/submissions.json
loader | Request: [POST] (http://pass-core:8080/data/submission)
loader | Request: [POST] (http://pass-core:8080/data/submission)
loader | Request: [POST] (http://pass-core:8080/data/submission)
loader | Request: [POST] (http://pass-core:8080/data/submission)
loader | > Response (http://pass-core:8080/data/submission)
loader | > Response (http://pass-core:8080/data/submission)
loader | > Response (http://pass-core:8080/data/submission)
loader | > Response (http://pass-core:8080/data/submission)
loader exited with code 0
docker compose -f docker-compose.yml -f eclipse-pass.local.yml up -d --no-build --quiet-pull --pull always
```
You will see various containers start. Once the `loader` container has started PASS should be available.

## Open browser

In your browser, navigate to [pass.local](https://pass.local).
In your browser, navigate to [http://localhost:8080].

![Welcome to PASS](../assets/passapp/welcome_screen.png)

Expand All @@ -113,27 +54,17 @@ And then you are authenticated and can view the PASS dashboard.

![PASS dashbaord](../assets/passapp/dashboard.png)


## Shutting down the demo

The running demo can be stopped with the following command
The running demo can be stopped with the following command:

```bash
./demo.sh down
docker compose -f docker-compose.yml -f eclipse-pass.local.yml down -v
```

## Troubleshooting

### `WARN[0000]` can be ignored
This will also delete volumes.

You might see warnings about unset variables. That is OK, but also feel free
to push a PR to address the code to no longer display these warnings.

```bash
WARN[0000] The "METADATA_SCHEMA_URI" variable is not set. Defaulting to a blank string.
WARN[0000] The "EMBER_GIT_BRANCH" variable is not set. Defaulting to a blank string.
WARN[0000] The "EMBER_GIT_REPO" variable is not set. Defaulting to a blank string.
```
## Troubleshooting

### Cannot connect to the Docker daemon

Expand All @@ -154,16 +85,4 @@ If you see an error like
failed to solve: rpc error: code = Unknown desc = failed to solve with frontend dockerfile.v0: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount2714819657/Dockerfile: no such file or directory
```

It's likely pulling all the images did not complete successfully. Re-run

```bash
./demo.sh pull
```


## References

* [Pass-docker prerequisites](https://github.com/eclipse-pass/pass-docker#prerequisites)



It's likely pulling all the images did not complete successfully. Try restarting.
Binary file added docs/dev/pass_authn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/dev/pass_authn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 14 additions & 14 deletions docs/dev/running-pass-ui-on-your-host-machine.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
In order to run pass-ui outside of the docker environment:

1) run docker compose commands with the local override files:
1) Configure the docker environment

You will need to configure `pass-core` to load the UI from `localhost:4200`.

This can be done by seting the environment variable `PASS_CORE_APP_LOCATION` to `http://host.docker.internal:4200/` in `.env`.

Then simply use docker compose like normal.

```
docker compose -f docker-compose.yml -f eclipse-pass.local.yml <your command here>
```
The local override yml and env contain entries relevant to allowing the pass-auth container to access the host machine's network and directing requests to the host machine.

In `eclipse-pass.local.yml` the relevant entry is the `extra_hosts`:
You may need to investigate other ways of accessing the host machine network, [see](https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host).

```
auth:
env_file:
- .eclipse-pass.local_env
extra_hosts:
- "host.docker.internal:host-gateway"
```
You may also consider stopping the pass-ui container.

In `.eclipse-pass.local_env` the relevant env var is `PASS_UI_URL=http://host.docker.internal:4200/`. Note, this will work on a MacOS environment, but may not work on all environments.
2) Run pass-ui on your host machine

You may need to investigate other ways of accessing the host machine network, [see](https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host).
Start ember on port 4200.

2) run pass-ui on your host machine with a proxy flag:
```
ember s --proxy=http://pass.local
ember s
```

Loading
Loading