Authorization
The Crane Server provides configuration properties for defining and customizing the authorization of each repository and/or sub-paths of repositories. There are two kinds of authorization provided by Crane “Path access” and “POSIX access”. Path access control is in the application.yml
file of the app and provides a few options to define which users should have access to the files in a specific directory (repository or sub-path). POSIX access control provides an additional access control layer using the POSIX (Portable Operating System Interface) permissions of the file system. Additionally as Crane allows both reading and writing of files it has decoupled the access control of these actions.
Path access
Configuring the access control for read and write requests work in the same way. Crane’s default access control disallows all access. Concretely this means that granting access control to any user or group of users needs to be done explicitly.
Crane server admins can define the path access control of each repository and path in the application.yml
file. Crane uses this definition to determine whether users have authorisation to do the requested action for a given path.
For example, to configure the path access of the example_repository
repository:
app:
repositories:
example_repository:
read-access:
# read access configuration
write-access:
# write access configuration
In addition to configuring the access control for the whole repository, it’s possible to define access control for paths inside a repository. This is completely optional, and not all paths that exist in the repository must be defined in the configuration. Crane checks the access control using the most specific configured path. For example:
app:
repositories:
example_repository:
read-access:
# read access configuration
write-access:
# write access configuration
paths:
my_path:
read-access:
# read access configuration for my_path
write-access:
# write access configuration for my_path
paths:
some_path:
read-access:
# read access configuration for some_path
write-access:
# write access configuration for some_path
another_path:
read-access:
# read access configuration for another_path
write-access:
# write access configuration for another_path
Crane determines if a user has access to a path in recursive manner. It starts
from the root, (i.e. a repository) and follows the path all the way down to the
requested directory or file. For example, if a user requests
/example_repository/my_path/some_path/file.txt
, Crane first checks the
authorization on example_repository
, then on my_path
and finally on
some_path
. If a user requests /example_repository/my_path/abc/file.txt
,
Crane first checks the authorization on example_repository
, and finally on
my_path
(no check is done for abc
, since is not specified in the
configuration file).
Read access
The read access of a repository or path is specified using the read-access
property.
By default (if the property is not specified), nobody has read access. Users making read requests to paths can get the following errors:
- 404 not found:
- when authenticated users visit an unauthorized repository or path
- when authenticated users visit an authorized, but non-existing path
- when unauthenticated users visit a non-existing path in a public repository or path
- 302 Found:
- when (using a browser) unauthenticated users visit an unauthorized path (no matter whether it exists)
- 401 unauthorized:
- when (not using a browser) unauthenticated users visit an unauthorized path (no matter whether it exists)
Write access
The write access of a repository or path is specified using the write-access
property.
Write access is completely independent of read access, therefore a user could have write access to a repository or path without having read access to it.
By default (if the property is not specified), nobody has write permission. Users making write requests to paths can get the following errors:
- 403 forbidden:
- when (un)authenticated users write to an unauthorized or non-existing repository or path
Reference
Crane provides the following properties to define read and write access:
Note
Crane allows using these options for defining access control on both repository and path level.Public
If set to true
a repository is accessible by any authenticated or unauthenticated user.
Note: sub-paths can only be public if their parents are also public.
app:
repositories:
repository:
read-access:
public: true
repository_with_paths:
read-access:
public: true
paths:
path1:
read-access:
public: true
path2:
read-access:
public: false # equivalent to default behavior, can be removed
In this example the two repositories (i.e. repository
and repository_with_paths
) are public. In the repository_with_paths
repository, path1
is public, however path2
isn’t accessible by any users.
app:
repositories:
repository:
write-access:
public: true
repository_with_paths:
write-access:
public: true
paths:
path1:
write-access:
public: true
path2:
write-access:
public: false # equivalent default behavior, can be removed
In this example the two repositories (i.e. repository
and repository_with_paths
) have public write access (i.e. any authenticated or unauthenticated user can upload files). In the repository_with_paths
repository, path1
is public, however nobody has write access to path2
(since no other access control is specified).
Users
The users
property grants access to users by listing their usernames.
app:
repositories:
repository:
read-access:
users: [ jeff, jack ]
repository_with_paths:
read-access:
users: [ jeff, jack ]
paths:
path1:
read-access:
users: [ jeff ]
path2:
path2_explicit:
read-access:
public: false
In this example the two repositories (i.e. repository
and repository_with_paths
) are accessible by jeff
and jack
. In the repository_with_paths
repository, path1
is only accessible by jeff
, path2
isn’t accessible by any user (since no access control is specified) and path2_explicit
explicitly defines the behaviour of path2
(i.e. it isn’t accessible by any user).
app:
repositories:
repository:
write-access:
users: [ jeff, jack ]
repository_with_paths:
write-access:
users: [ jeff, jack ]
paths:
path1:
write-access:
users: [ jeff ]
path2:
path2_explicit:
write-access:
public: false
In this example, jeff
and jack
have write access to the two repositories (i.e. repository
and repository_with_paths
). In the repository_with_paths
repository, jeff
can write to path1
, path2
isn’t writable by any user (since no access control is specified) and path2_explicit
explicitly defines the behaviour of path2
(i.e. it isn’t writable by any user).
Groups
The groups
property grants access to groups of users by listing the group names.
app:
repositories:
repository:
read-access:
groups: [ SCIENTISTS ]
repository_with_paths:
read-access:
groups: [ SCIENTISTS, MATHEMATICIANS ]
paths:
path1:
read-access:
groups: [ SCIENTISTS ]
In this example, repository
is accessible by any user part of the SCIENTISTS
group, and repository_with_paths
is accessible by any user part of the SCIENTISTS
or MATHEMATICIANS
groups. In the repository_with_paths
repository, only users part of the SCIENTISTS
group can access path1
.
app:
repositories:
repository:
write-access:
groups: [ SCIENTISTS ]
repository_with_paths:
write-access:
groups: [ SCIENTISTS, MATHEMATICIANS ]
paths:
path1:
write-access:
groups: [ SCIENTISTS ]
In this example, repository
is writable by any user part of the SCIENTISTS
group, and repository_with_paths
is writable by any user part of the SCIENTISTS
or MATHEMATICIANS
groups. In the repository_with_paths
repository, only users part of the SCIENTISTS
group can write to path1
.
Network
The network
property grants access to users when they make request from specific ip-address or ip-ranges.
app:
repositories:
repository:
read-access:
network: 11.11.11.11
repository_with_paths:
read-access:
network: 22.22.22.22
paths:
path1:
read-access:
network: 33.33.33.33
In this example repository
is accessible for users if their network IP is 11.11.11.11
. The repository_with_paths
repository is accessible for users from IP address 22.22.22.22
. In the repository_with_paths
, path1
isn’t accessible to any users as users can’t have multiple IP addresses.
app:
repositories:
repository:
write-access:
network: 11.11.11.11
repository_with_paths:
write-access:
network: 22.22.22.22
paths:
path1:
write-access:
network: 33.33.33.33
In this example repository
is writable by users if their network IP is 11.11.11.11
. The repository_with_paths
repository is writable by users from IP address 22.22.22.22
. In the repository_with_paths
, path1
isn’t accessible to any users as users can’t have multiple IP addresses.
SpEL expression
The expression
property makes it possible to create more complex authorizations checks using SpEL expressions. Crane exposes the following properties that you can use:
groups
: list of groups the user is part ofclaims
: list of claims assigned to the user
app:
repositories:
repository1:
read-access:
expression: "#{groups.contains('SCIENTISTS') and groups.contains('MATHEMATICIANS')}"
repository2:
read-access:
expression: "#{groups.contains('SCIENTISTS') and !groups.contains('MATHEMATICIANS')}"
In this example repository1
is accessible for users that are part of both the SCIENTISTS
and MATHEMATICIANS
groups, while repository2
is only accessible for users that are in the SCIENTISTS
group and not in the MATHEMATICIANS
group.
app:
repositories:
repository1:
write-access:
expression: "#{groups.contains('SCIENTISTS') and groups.contains('MATHEMATICIANS')}"
repository2:
write-access:
expression: "#{groups.contains('SCIENTISTS') and !groups.contains('MATHEMATICIANS')}"
In this example repository1
is writable by users that are part of both the SCIENTISTS
and MATHEMATICIANS
groups, while repository2
is only writable by users that are in the SCIENTISTS
group and not in the MATHEMATICIANS
group.
Any authenticated user
If the any-authenticated-user
property is true
, the repository is accessible by any authenticated user (but not by unauthenticated users).
app:
repositories:
repository:
read-access:
any-authenticated-user: true
repository_with_paths:
read-access:
public: true
paths:
path1:
read-access:
any-authenticated-user: true
path2:
read-access:
any-authenticated-user: false # equivalent to default behavior, can be removed
In this example, repository
is accessible for any authenticated user. The repository_with_paths
repository is accessible for unauthenticated and authenticated users. In addition, path1
is accessible for authenticated users while path2
isn’t accessible for any user.
app:
repositories:
repository:
write-access:
any-authenticated-user: true
repository_with_paths:
write-access:
public: true
paths:
path1:
write-access:
any-authenticated-user: true
path2:
write-access:
any-authenticated-user: false # equivalent to default behavior, can be removed
In this example, repository
is writable by any authenticated user. The repository_with_paths
repository is writable by unauthenticated and authenticated users. In addition, path1
is writable by authenticated users while path2
isn’t writable by any user.
Restrictions
Crane puts some restrictions to the combination of properties, therefore all of the following isn’t allowed:
- using
public: true
on a path in a repository or path that doesn’t havepublic: true
- using
public: true
together with any other access control property in that access control block - using
any-authenticated-user: true
together with theusers
,groups
orexpression
property
Advanced example
This section summarizes the previous sections using a concrete example config:
app:
repositories:
nesting:
read-access:
groups: [ SCIENTISTS, MATHEMATICIANS ]
paths:
level1:
read-access:
groups: [ RESTRICTED ]
paths:
level2:
read-access:
groups: [ CONFIDENTIAL ]
other_level2:
write-access:
groups: [ CONFIDENTIAL ]
Scenario 1
Given the preceding config, when a user tries to read the contents of the nesting
repository, Crane performs the following checks to determine whether the user has access:
- is the user authenticated?
- is the user part of the
SCIENTISTS
orMATHEMATICIANS
groups?
If all checks succeeded, the user gets (read) access to the nesting
repository.
Scenario 2
Given the preceding config, when a user tries to read the contents of the level1
path, Crane performs the following checks to determine whether the user has access:
- is the user authenticated?
- is the user part of the
SCIENTISTS
orMATHEMATICIANS
groups? - is the user part of the
RESTRICTED
group
If all checks succeeded, the user gets (read) access to the level1
repository.
In summary users get read access to level1
if they’re authenticated, part of either the SCIENTISTS
or MATHEMATICIANS
groups and part of the RESTRICTED
group.
Scenario 3
Given the preceding config, when a user tries to read the contents of the other_level2
path, Crane immediately denies the request since other_level2
has no read-access
defined.
POSIX
Crane allows the usage of POSIX access control for a storage location. The app.repositories.<REPOSITORY_NAME>.posix-access-control
property configures POSIX access control on repository level and is false
by default.
POSIX is automatically enabled for all paths in the repository.
When using POSIX access control, both the path access control and POSIX filesystem permissions are used to determine whether a user has read or write access for a specified directory or file.
A user only has access to a directory or file when both access control systems grant access.
When it comes to POSIX permissions Crane only uses the read (r
) and write (w
) permissions of the user or group.
The execution (x) and any other permissions aren’t used.
Write permissions
When creating new files with POSIX access control enabled, Crane doesn’t follow the standard rules set by POSIX. If Crane would strictly follow the POSIX standard, new files would only be visible to the user that initiated the upload and members of their primary group. Therefore, Crane uses a simpler and more intuitive approach, overwriting the permissions of newly created files with the permissions of their directory. This way the newly created files are visible to the same users as the directory they’re in.
Crane permissions
Crane needs heightened permissions to be able to create files and to change their owner, group, and permissions. To grant Crane the needed permissions one can use a docker container with capabilities. In particular we recommend usingCAP_CHOWN
, CAP_FOWNER
and CAP_DAC_OVERRIDE
. It’s not recommended to run Crane with root permissions.