Skip to content
Open
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

## [Unreleased]

### Security

- Webadmin `password.generate`: generate a random password upon start up when none is configured, and log it.
**Breaking change**: this defaults to `true`, thus WebAdmin is no longer unauthenticated out of the box, existing
deployments included. Set `password.generate=false` in `webadmin.properties` to opt back into an unauthenticated
WebAdmin, or configure `password` to pin a stable secret.

This release brings the following significant changes:

- Upgrade TCP protocols to Netty 4
Expand Down
10 changes: 8 additions & 2 deletions docs/modules/servers/pages/15-minute-demo.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ Run this command to create the `webadmin.properties` file:

[source,bash]
----
printf 'enabled=true\nport=8000\nhost=localhost' >> webadmin.properties
printf 'enabled=true\nport=8000\nhost=localhost\npassword.generate=false\n' >> webadmin.properties
----

Explanation:

* `enabled=true` instructs James to run the Admin API service
* `port=8000` configures the Admin API to be made available via port 8000
* `host=localhost` configures the Admin API to respond on localhost
* `password.generate=false` disables WebAdmin authentication for this local demo

[NOTE]
====
This demo explicitly disables WebAdmin password generation to keep the first-run experience simple.
By default, `password.generate` is enabled and James generates a random WebAdmin password at startup when no
`password` is explicitly configured. Do not disable WebAdmin authentication when exposing it beyond this local demo.
====

Now run the James demo server using this command:

Expand Down Expand Up @@ -219,4 +226,3 @@ docker stop james ; docker rm james
----

That's all, folks!

10 changes: 9 additions & 1 deletion examples/custom-webadmin-route/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,20 @@ enabled=true
port=8000
host=localhost

# Disable WebAdmin authentication for this local customization demo.
# Password generation defaults to true when no password is explicitly configured.
password.generate=false

# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
extensions.routes=org.apache.james.examples.RouteA
```

This example explicitly disables WebAdmin password generation to keep the customization demo simple. By default,
`password.generate` is enabled and James generates a random WebAdmin password at startup when no `password` is
explicitly configured. Do not disable WebAdmin authentication when exposing it beyond this local demo.

Create a keystore (default password being `james72laBalle`):

```
Expand All @@ -76,4 +84,4 @@ You can play with `curl` utility with the resulting server:
```
$ curl -XGET http://172.17.0.2:8000/hello/a
RouteA
```
```
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ enabled=true
port=8000
host=localhost

# Disable WebAdmin authentication for this local customization demo.
# Password generation defaults to true when no password is explicitly configured.
password.generate=false

# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Generate a random password upon start up when no password is configured.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,15 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true

# Configure one or more passwords (comma separated) for WebAdmin authentication
#password=secret1,secret2
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ chmod +x provision.sh
sudo apt-get install postfix
----

* Retrieve the generated WebAdmin password from the James startup logs and expose it to the provisioning script:
----
export WEBADMIN_PASSWORD="replace-with-generated-webadmin-password"
----

Omit this variable only when WebAdmin password authentication is explicitly disabled.

* Run the provision script:
----
./provision.sh
Expand Down Expand Up @@ -98,4 +105,3 @@ A sample IMAP performance testing result (PlatformValidationSimulation):
image::james-imap-base-performance.png[]

If you get a IMAP performance far below this base performance, you should consider investigating for performance issues.

Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
#!/bin/bash

set -eu

export WEBADMIN_BASE_URL="http://localhost:8000"
export SMTP_URL="localhost:25"
export DOMAIN_NAME="domain.org"
export USERS_COUNT=10
export DUMMY_MAILBOXES_COUNT=10
export DUMMY_EMAILS_COUNT=100

call_webadmin() {
if [ -n "${WEBADMIN_PASSWORD:-}" ]; then
curl --fail --header "Password: ${WEBADMIN_PASSWORD}" "$@"
else
curl --fail "$@"
fi
}

# Create domain
curl -X PUT ${WEBADMIN_BASE_URL}/domains/${DOMAIN_NAME}
call_webadmin -X PUT ${WEBADMIN_BASE_URL}/domains/${DOMAIN_NAME}

for i in $(seq 1 $USERS_COUNT)
do
# Create user
echo "Creating user $i"
username=user${i}@$DOMAIN_NAME
curl -XPUT ${WEBADMIN_BASE_URL}/users/$username \
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/$username \
-d '{"password":"secret"}' \
-H "Content-Type: application/json"

# Create mailboxes for each user
echo "Creating user $i mailboxes"
# Create some basic mailboxes
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/INBOX
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Outbox
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Sent
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Draft
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Trash
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/INBOX
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Outbox
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Sent
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Draft
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/Trash

# Create some other dummy mailboxes
for j in $(seq 1 $DUMMY_MAILBOXES_COUNT)
do
dummyMailbox=MAILBOX${j}
curl -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/$dummyMailbox
call_webadmin -XPUT ${WEBADMIN_BASE_URL}/users/${username}/mailboxes/$dummyMailbox
done
done

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
The web administration supports for now the CRUD operations on the domains, the users, their mailboxes and their quotas,
managing mail repositories, performing cassandra migrations, and much more, as described in the following sections.

*WARNING*: This API allows authentication only via the use of JWT. If not
configured with JWT, an administrator should ensure an attacker can not
use this API.
*WARNING*: This API supports authentication via a static password or JWT. If no
authentication mechanism is configured, an administrator should ensure an attacker
can not use this API.

By the way, some endpoints are not filtered by authentication. Those endpoints are not related to data stored in James,
for example: Swagger documentation & James health checks.
Expand Down Expand Up @@ -35,6 +35,49 @@ to get some examples and hints.
| cors.origin
| Specify ths CORS origin (default: null)

| password.generate
| Generates a random password upon start up when no `password` is configured, allowing a secure setup without
hardcoded credentials (default: true). As such, WebAdmin is never unauthenticated unless explicitly asked for.

....
password.generate=false
....

The generated password is written in the logs upon start up:

....
WARN No WebAdmin password had been configured: a random one had been generated for this run. [...]
Generated WebAdmin password: 8Kj2mXqT4vZ...
....

Beware: the generated password changes upon each restart, and is exposed to whoever can read the logs. Configure
`password` explicitly for setups needing a stable secret, or set `password.generate=false` to opt back into an
unauthenticated WebAdmin. This option is ignored when `password` is configured, when `jwt.enabled` is true, and when
WebAdmin is disabled.

| password
| Uses a configured static value for authentication. It relies on the `Password` header.
It supports several passwords, configured as a comma-separated list.

....
password=secretA,secretB,secretC
....

This allows requests with:

....
Password: secretA
Password: secretB
....

But denies:

....
Password: secretD
....

Requests without the `Password` header are denied as well.

| jwt.enable
| Allow JSON Web Token as an authentication mechanism (default: false)

Expand Down Expand Up @@ -97,4 +140,4 @@ The public key can be referenced as `jwt.publickeypem.url` of the `jmap.properti

WebAdmin adds the value of `X-Real-IP` header as part of the logging MDC.

This allows for reverse proxies to cary other the IP address of the client down to the JMAP server for diagnostic purpose.
This allows for reverse proxies to cary other the IP address of the client down to the JMAP server for diagnostic purpose.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ Where :

- HOSTNAME: is the hostname you want to give to your James container. This DNS entry will be used to send mail to your James server.

Webadmin port binding is restricted to loopback as users are not authenticated by default on webadmin server. Thus you should avoid exposing it in production.
Webadmin port binding is restricted to loopback. Webadmin is protected by a password randomly generated upon
each start up and written in the logs (see `password.generate`), yet you should avoid exposing it in production.
Note that the above example assumes `127.0.0.1` is your loopback interface for convenience but you should change it if this is not the case on your machine.

If you want to pass additional options to the underlying java command, you can configure a _JAVA_TOOL_OPTIONS_ env variable, for example add:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,15 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true

# Configure one or more passwords (comma separated) for WebAdmin authentication
#password=secret1,secret2
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,15 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true

# Configure one or more passwords (comma separated) for WebAdmin authentication
#password=secret1,secret2
10 changes: 9 additions & 1 deletion server/apps/jpa-app/docker-configuration/webadmin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true
13 changes: 12 additions & 1 deletion server/apps/jpa-app/sample-configuration/webadmin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,15 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true

# Configure one or more passwords (comma separated) for WebAdmin authentication
#password=secret1,secret2
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@ https.enabled=false
# List of fully qualified class names that should be exposed over webadmin
# in addition to your product default routes. Routes needs to be located
# within the classpath or in the ./extensions-jars folder.
#extensions.routes=
#extensions.routes=

# Password authentication settings

# Generate a random password upon start up when no password is configured below.
# The generated password is written in the logs, and changes upon each restart.
# Set it to false to run WebAdmin without any authentication.
# Defaults to true
password.generate=true
Loading