Open NorseGaud opened 3 years ago
Here we go:
openapi: 3.0.1
info:
title: Docker-mailserver Administration API
version: 0.0.1
servers:
- url: 'https://contoso.com/'
paths:
/api/admin/v1/users/{emailAddress}/changePassword:
post:
summary: Changes a given user's password
tags:
- V1 User operations
- V1 Admin API
security:
- ApiKeyAuth: []
parameters:
- in: path
name: emailAddress
required: true
schema:
type: string
requestBody:
description: The new password for the target user
content:
application/json:
schema:
type: string
responses:
'204':
description: The password was successfully modified
'404':
$ref: '#/components/responses/UserNotFoundError'
'401':
$ref: '#/components/responses/UnauthorizedError'
components:
schemas:
ErrorBase:
type: object
required:
- errorCode
- message
properties:
errorCode:
type: string
description: Code name of the error
message:
type: string
description: Additional details about the error
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY
responses:
UserNotFoundError:
description: User does not exist
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorBase'
UnauthorizedError:
description: API key is missing or invalid
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorBase'
You can copy & paste this in https://editor.swagger.io/ to see how it would look like
Key points:
errorCode
X-API-KEY
headerFeel free to discuss any point from the spec in that issue. Next step will be generating the app skeleton, I'll do it during the week. I already started, based on another spec, so there shouldn't be much to be done
Sounds and looks good. Nothing stuck out as problematic to me.
Small question: I'm a novice, so I'm curious if it's typical to have /user/{username} and a separate /users which would list all users for APIs? The plural /users/{email}/changePassword is grammatically odd to me.
While I've seen the debate between plural and singular, I've never seen an API where you have both. Doing this, you somewhat break the clear hierarchy so I don't think it's common at all. I don't claim to know everything though, obviously!
Maybe reading that as "From /users, change the password of {email}" might help grammatically :)
When it comes to all plural vs all singular, I prefer to have plural because "/user" for listing looks weird to me.
Resources that might be of interest: https://jsonapi.org/recommendations/#urls-resource-collections
JsonAPI is a nicely specified way to design an API, so I like to take inspiration from there!
I'm not sure the API-Key Auth is enough for users changing their password by them self. I think it is neccessary for this use case to authenticate by old password?
@DerOetzi I have looked into that possibility, and that's even what I wanted to do in the first place. However, when trying to do a dummy implementation some weeks ago, I noticed it wasn't so simple: we wouldn't be able to use the shell functions from docker-mailserver, we'd need to read the postfix-accounts.cf
file, parse it to get the user, get the salt and finally we can check if given old password is good.
While it is doable, it seems that users mostly wanted to have a layer above the API with a simple key, meaning -I assumed-, they'd manage authentication on their UI instead.
With that in mind, I therefore prefixed this api with /admin
to make it clear it's not intended to users. If there's a demand for self-service as well, we can always add a route later on under a /self
section to the API.
But how is a single user getting his personal API-Key? Let us asume their a two users user_a@domain.com and user_b@domain.com. How is secured that user_a@domain.com can only change it's own password and not of user_b@domain.com?
There is no personal API key for /admin
. From what I've gathered from the other thread, the aim was to have an admin API/panel, and some people wanted to have an API that could be used by another component (webmail, another UI). In the latter case, as mentioned above, the user authentication is another layer.
Again, that doesn't prevent having /self
routes on the side, which would be based on the user's current password anyway.
Does this also address forgotten passwords?
I mean sending a one-time hash link to a user-defined address (which will be checked for existence and if not existent, no reply - not even about non-existence! - will be issued) with a form to change password. Or something along that line.
This helps enormously in practice as passwords are number one reason to contact the admin/support.
Right now this doesn't. This could become a feature of the admin API, but it is currently out of scope. For now the goal is to provide a simple yet useful API with the first requested use case. Other features can be discussed when that base is available :)
I got here from https://github.com/docker-mailserver/docker-mailserver/issues/2092
This is certainly interesting - and I'd like to suggest that the API expand to at minimum all of the commands you can perform via docker exec -it mailserver setup
- is that the intent? Or is this scoped more narrowly?
This is certainly interesting - and I'd like to suggest that the API expand to at minimum all of the commands you can perform via
docker exec -it mailserver setup
- is that the intent?
I don't know all of them, but for there should be no issue with having them all available with the API
I believe the password change capability would be setup email update <email> <password>
Here is a full list of the commands supported by setup
[SUB]COMMANDS
COMMAND email :=
/usr/local/bin/setup email add <EMAIL ADDRESS> [<PASSWORD>]
/usr/local/bin/setup email update <EMAIL ADDRESS> [<PASSWORD>]
/usr/local/bin/setup email del [ OPTIONS... ] <EMAIL ADDRESS> [ <EMAIL ADDRESS>... ]
/usr/local/bin/setup email restrict <add|del|list> <send|receive> [<EMAIL ADDRESS>]
/usr/local/bin/setup email list
COMMAND alias :=
/usr/local/bin/setup alias add <EMAIL ADDRESS> <RECIPIENT>
/usr/local/bin/setup alias del <EMAIL ADDRESS> <RECIPIENT>
/usr/local/bin/setup alias list
COMMAND quota :=
/usr/local/bin/setup quota set <EMAIL ADDRESS> [<QUOTA>]
/usr/local/bin/setup quota del <EMAIL ADDRESS>
COMMAND config :=
/usr/local/bin/setup config dkim [ ARGUMENTS... ]
COMMAND relay :=
/usr/local/bin/setup relay add-domain <DOMAIN> <HOST> [<PORT>]
/usr/local/bin/setup relay add-auth <DOMAIN> <USERNAME> [<PASSWORD>]
/usr/local/bin/setup relay exclude-domain <DOMAIN>
COMMAND debug :=
/usr/local/bin/setup debug fetchmail
/usr/local/bin/setup debug fail2ban [unban <IP>]
/usr/local/bin/setup debug show-mail-logs
/usr/local/bin/setup debug inspect
/usr/local/bin/setup debug login <COMMANDS>```
Isn't doing these changes via setup
a security risk because it requires root privileges, or at least the privileges docker is running with? I am not an expert, but somehow feel it would be better to 'export' these function from docker-mailserver (and only these!) through a simple interface (does not have to be http-based), or modify the account files directly.
Yes and no.
The dockermailserver container runs as root. So that as a whole is the main security issue.
setup
also runs as root - but part of that is to ensure that it can read/write to all of the files. If the dockermailserver project as a whole decided to be more strict on file ownership/permissions - it would be possible to have the setup script drop permissions and run as the 'user'.
Of course - that is exactly the same restrictions you'd need to create a limited API as you describe.
It is unlikely due to the software stack dockermailserver is built on to avoid the container running as root. Possible, but probably more trouble than it is worth.
Yes and no.
The dockermailserver container runs as root. So that as a whole is the main security issue.
setup
also runs as root
Yes, but isn't the difference that setup
(or docker exec -ti ... setup ...
) would have to be run as root on the host, not in a container ?
You are correct that either you have configured docker such that users can run docker (which in itself is a security risk) or you have to be root to issue the docker command.
I do think you've interpreted the setup
command incorrectly in this thread. I had brought this up because today - the setup command offers a suite of features. The API should probably includes all of these features. How the API decides to implement these features - well that's up to the API.
Today - with dockermailserver if you modify the config files - the container notices and refreshes. You don't have to use setup
Related: https://github.com/docker-mailserver/docker-mailserver-admin/issues/3
Goal: Discuss and Create the v1 API spec to use with in the app