Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
16 changes: 1 addition & 15 deletions .github/workflows/deploy-documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,11 @@ jobs:
run: |
pip install -q -r requirements.txt

- name: build admin docs
- name: build docs
working-directory: docs/guides/admin/
run: |
python -m mkdocs build

- name: generate list of committers
working-directory: docs/guides/developer/
env:
GITHUB_USER: ${{ secrets.GH_USER }}
GITHUB_PA_TOKEN: ${{ secrets.GH_PA_TOKEN }}
run: |
./.generate-list-of-committers.sh

- name: build developer docs
working-directory: docs/guides/developer/
run: |
python -m mkdocs build

- name: build landing page
if: github.ref == 'refs/heads/develop'
working-directory: docs/guides/.infrastructure/
Expand Down Expand Up @@ -103,7 +90,6 @@ jobs:
run: |
mkdir -p docs.opencast.org/"${GITHUB_REF#refs/heads/}"
mv -v docs/guides/admin/site docs.opencast.org/"${GITHUB_REF#refs/heads/}/admin"
mv -v docs/guides/developer/site docs.opencast.org/"${GITHUB_REF#refs/heads/}/developer"
git log -n1 > docs.opencast.org/"${GITHUB_REF#refs/heads/}/commit"

- name: commit new version
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ node/

# Ignore mkdocs sites and python virtualenv (docs/guides/readme.md)
docs/guides/*/site
docs/guides/*/mkdocs.log
docs/guides/venv

# Ignore Makefiles
Expand Down
2 changes: 1 addition & 1 deletion docs/checkstyle/check-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set -ue
ret=0
cd docs/guides

for docs in admin developer; do
for docs in admin; do
cd $docs
if test "$( grep -r 'opencast_major_version[()]*}\|{opencast_major_version' )" != ""; then
echo "Error, $docs has a syntax error related to opencast_major_version:"
Expand Down
30 changes: 3 additions & 27 deletions docs/guides/.infrastructure/index.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
<!-- Example row of columns -->
<div class="row">
<div class="col-md-6">
<h2><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span> Adopters Guide</h2>
<p>The Opencast adopters guide contains official release documentation and installation and configuration details.</p>
<h2><span class="glyphicon glyphicon-tasks" aria-hidden="true"></span> Opencast Documentation</h2>
<p>The Opencast documentation contains official release documentation, installation and configuration details,
as well as developer information.</p>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="adminGuideVersions" data-toggle="dropdown" aria-expanded="true">
Select a version
Expand All @@ -53,31 +54,6 @@
</ul>
</div>
</div>
<div class="col-md-6">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section should remain, but link to the correct place in the documentation.

<h2><span class="glyphicon glyphicon-wrench" aria-hidden="true"></span> Developer Guide</h2>
<p>The Opencast developer guide contains information for active developers and those who want to become involved.</p>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="adminGuideVersions" data-toggle="dropdown" aria-expanded="true">
Select a version
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1" id="developerGuides">
{% for version in version_info -%}
<li role="presentation">
<a role="menuitem"
tabindex="-1"
href="//docs.opencast.org/{{ version['branch'] }}/developer"
style="display: flex; justify-content: space-between;">
<span>{{ version['name'] }}</span>
{%- if version['attribute'] -%}
<span style="color: #888; font-size: smaller">({{ version['attribute'] }})</span>
{%- endif %}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>

<hr>
Expand Down
1 change: 1 addition & 0 deletions docs/guides/admin/docs/developer/architecture/admin-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# In construction
78 changes: 78 additions & 0 deletions docs/guides/admin/docs/developer/architecture/api/agents-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
[TOC]
# General

The Agents API is available since API version 1.1.0.

### GET /api/agents

Returns a list of capture agents.

Query String Parameter | Type | Description
:----------------------|:----------------------------|:-----------
`limit` | [`integer`](types.md#basic) | The maximum number of results to return for a single request (see [Pagination](usage.md#pagination))
`offset` | [`integer`](types.md#basic) | The index of the first result to return (see [Pagination](usage.md#pagination))


__Sample request__

```xml
https://opencast.example.org/api/agents?limit=5&offset=1
```

__Response__

`200 (OK)`: A (potentially empty) list of capture agents is returned as JSON array of JSON objects

Field | Type | Description
:----------|:-------------------------------------|:-----------
`agent_id` | [`string`](types.md#basic) | The technical identifier of the capture agent
`status` | [`string`](types.md#basic) | The status of the capture agent
`inputs` | [`array[string]`](types.md#array) | The inputs of the capture agent
`update` | [`datetime`](types.md#date-and-time) | The last date and time this capture agent contactec the server
`url` | [`string`](types.md#basic) | The URL as reported by the capture agent


__Example__

```
[
{
"agent_id": "ca24",
"status": "offline",
"inputs": ["default"],
"update": "2018-03-12T18:17:25Z",
"url": "127.0.0.1"
}
]
```

### GET /api/agents/{agent_id}

Returns a single capture agent.

__Response__

`200 (OK)`: The capture agent is returned as JSON object

Field | Type | Description
:----------|:-------------------------------------|:-----------
`agent_id` | [`string`](types.md#basic) | The technical identifier of the capture agent
`status` | [`string`](types.md#basic) | The status of the capture agent
`inputs` | [`array[string]`](types.md#array) | The inputs of the capture agent
`update` | [`datetime`](types.md#date-and-time) | The last date and time this capture agent contactec the server
`url` | [`string`](types.md#string) | The URL as reported by the capture agent


`404 (NOT FOUND)`: The specified capture agent does not exist.

__Example__

```
{
"agent_id": "ca24",
"status": "offline",
"inputs": ["default"],
"update": "2018-03-12T18:17:25Z",
"url": "127.0.0.1"
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

[figure_2]: media/img/figure_2.png "Figure 2: Authentication and authorization based on Basic Authentication"

# Introduction

The External API’s security layer is designed to support a multitude of mechanisms for authentication such as API
keys, digest authentication and others. While the current implementation only supports basic authentication, further
authentication mechanisms may be added in the future.

# Basic Authentication
The External API is protected by basic authentication, requiring a user and a password be sent in the form of the
standard HTTP `Authorization` header. (see [Figure 2](#figure_2)). In the header, the username and password are sent
encoded in Base64 format. The incoming requests are matched against an existing user whose password needs to match with
the one that is found in the Authorization request header.

NOTE: Basic authentication is not activated by default, please activate it in the security settings
(`etc/security/mh_default_org.xml`) before using the External API.

<center>
![][figure_2]
</center>
<a name="figure_2"></a>Figure 2: Authentication and authorization based on Basic Authentication

## Protection of authentication data
Since Base64 is by no means regarded as encryption in the sense of security, it is strongly recommended to only offer
access to the External API over HTTPS rather than over HTTP in order to avoid unprotected transmission of the
username and password via the Authorization header.


## Validation criteria
When initiating the connection, the External API analyzes the header and extracts the username to match against an
existing API user. If that user is found, the connection is authenticated, otherwise it’s rejected.
110 changes: 110 additions & 0 deletions docs/guides/admin/docs/developer/architecture/api/authorization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

# External API

## Introduction

The External API can be accessed in two different ways: Either using a single dedicated user with access to
everything (“super user”) or by implementing more fine grained access through user and role switching upon every request
(“user switching” or “sudo” execution mode), where the request is executed in the name and using the roles of the
specified user.

The first method is ideal for scenarios where the end users of the external application are not managed in Opencast. The
downside of this approach is a potential security risk as well as the inability to audit and track changes made by the
external applications back to the actual user who actually triggered the changes. The second method is more cumbersome
to implement but leads a much improved control and assessment of security.

## Delegation of Authorization

In situations where the provider of the External API offers a super user who is allowed “sudo” requests that are
executed on behalf of another user, the External API is actually delegating authorization to the client application. In
this cause authorization is performed upon login of the super user, but then the super user can switch to any other user
or any set of roles (with a few exceptions for security reasons).

Note that in order to allow for user switching, a specific role needs to be assigned to the super user, and that role
cannot be obtained by manipulating the role set (see [Role switching](#role-switching)).

### User switching

When working with a super user, it is considered a best practice to specify a dedicated execution user upon each request
whenever possible and reasonable. This way, creation or modification of resources can later be audited and mapped back
to that user if needed.

The execution user can be specified by setting the `X-RUN-AS-USER` request header with the user name as its value, as
seen in this sample request:

Request | Headers
:-----------------|:------------------------------------------------------------
`GET /api` | `X-RUN-AS-USER: john.doe`



Switching to another user can potentially fail for various reasons: The user might not exist or may not be allowed to
switch to due to potential privilege escalation, or the current user might not be allowed to switch users at all.

If the request to switch to another user fails, the following response codes are returned:

Response code | Comment
:-------------------------|:---------------------------------------------------
`403 (FORBIDDEN)` | The current user is not allowed to switch users
`403 (FORBIDDEN)` | The user cannot be switched to due to potential escalation of privileges
`412 Precondition failed` | The user specified in the X-RUN-AS-USER header does not exist


### Role switching

Rather than specifying an execution user, the client might choose to specify a set of roles that should be used when
executing the request. This technique is recommended in cases where the users are not managed by the External API. By
specifying a set of roles, the corresponding request will be executed using the API’s anonymous user but equipped
with the specified set of roles.

The execution user’s roles can be specified by setting the `X-RUN-WITH-ROLES` request header with the set of roles as
its value and with individual roles separated by comma, as seen in this sample request:

Request | Headers
:-----------------|:------------------------------------------------------------
`GET /api` | `X-RUN-WITH-ROLES: ROLE_A,ROLE_B`

Switching to a set of roles can potentially fail for various reasons: The role may not be granted to due to potential
privilege escalation, or the current user might not be allowed to switch roles at all. If the request to apply a set of
roles fails, the following response codes are returned:

Response code | Comment
:-------------------------|:---------------------------------------------------
`403 (FORBIDDEN)` | The current user is not allowed to switch roles
`403 (FORBIDDEN)` | The roles cannot be granted to due to potential escalation of privileges


## Best practice

### One user per external application

As a best practice, the External API provider should create one super user per external application and tenant, so that
access through that super user can be controlled, limited and turned off individually for each external application and
tenant.

### Preference for user and role switching

Client implementations accessing the External API through a super user are urged to implement and enforce user and role
switching as much as possible, since it allows for auditing of user activity on the External API and introduces less
risk by running requests with a limited set of privileges.

Obviously, if all requests are executed using the super user directly, it is not possible to track which user initiated
a given action.

## Access Control

Most events in Opencast come with an access control list (ACL), containing entries that map actions to roles, either
allowing or denying that action. Opencast currently only supports the ability to explicitly allow an action and consider
everything else to be denied.

### Roles

When a user authenticates against Opencast, it is assigned its set of roles that determine the user's access to Opencast
data entities. There are multiple ways to associate roles with a user:

1. Explicit assignment directly to the user
2. Directly through membership in groups (ROLE_GROUP_&lt;group name&gt;)
3. Indirectly through membership in groups (whatever roles have been assigned to the group)

In addition, a special role is assigned that uniquely identifies a user ("user role"). The user role can be determined by
evaluating the `userrole` attribute in the Base API's call to [/info/me](../base-api/#get-apiinfome).
Loading