Hello Jean,
that was a nice read. Thank you very much for it.
With the linked example I got it work.
As I mentioned: I don't see my example to use mutual TLS as a way the
James project should implement to protect the webadmin. The JWT already
does a good job. And although it's possible to revoke certificates it
requires to also setup and provide CRL or OCSP - additional services
equalizing its benefits.
I guess a good option would be a reverse proxy: While the proxy uses the
JWT internal to communicate with James as its backend its frontend
controls the user access (if I'm not wrong on this httpd also provides
means to interact with LDAP). This way if the JWT needs to be rotated it
only has to be changed at two places: James and the reverse proxy.
So, for anyone who might on the road to devlope any kind of client: as
JWT is already implemented in James that's the way to go.
Anyway - nice topic overall. I enjoyed the activity around it.
Have a nice weekend everyone.
Matt
Am 19.02.25 um 23:28 schrieb Jean Helou:
hi everyone,
I finally had the time to take a look at the code.
With regards to setting up https for webmin
Sadly spark's code forces us to go through a keystore, there is no way to
bypass that without changing spark. One option I have not yet investigated
is building a keystore from a more classic crt+key or pem file setup on
startup and passing that to spark.
With regards to authentication:
As has been said: the 2 current choices are no authentication or JWT.
The JWT setup is exactly the same as a token based setup, using
cryptography doesn't bring much since a captured token cannot be
invalidated unless I missed something.
The documentation on how to setup such a token can be found at
https://james.staged.apache.org/james-project/3.9.0/servers/distributed/configure/webadmin.html#_generating_a_jwt_key_pair
It boils down to creating an asymmetric key pair (private + public keys)
You provide the public key (pem file) of the certificate to james so it can
verify the provided tokens
You can then use the private key to sign as many JWT tokens as needed.
James verifies the received tokens against the public key then parses the
claims in the token if the signature is valid.
When you want to use the token to authenticate you send it in the standard
`Authentication: Bearer $TOKEN` http header just like any other bearer
token authentication scheme.
It protects against bruteforcing the authentication token as it would
require bruteforcing the private key which can be quite difficult depending
on the algorithm and keysize you choose.
It does not protect you against replay attacks so one must ensure the token
is never leaked.
Of course the private key must never be leaked either or it could be used
to generate a rogue valid token.
The documentation suggests RSA 4096, but you should be able to use elliptic
curve keys instead if you are worried about qantum cryptography. I would
say that following the latest best practices for SSH keys would be a good
enough starting point.
The idea is that using JWT we can have auditability and we could build
different tokens with different grants, allowing us to manage granular
permission levels.
For now james can only understand 2 things in the JWT token :
- a login in the `sub=` attribute
- a claim to the admin role in the `c=` attribute
If your token doesn't have the admin claim you will not be authorized even
if the token is properly signed.
The main benefit I can see to the current JWT scheme over a basic token
based approach is auditability of admin actions.
Another benefit is that it doesn't require any storage on james side.
A couple drawbacks :
- the inability to revoke a token without rotating the entire key and all
the corresponding tokens, this can be ok for smaller deployments but could
become problematic for larger deployments.
- the usual risk associated with any private key based scheme it is only as
strong as the user's ability to protect that secret key.
- it makes the initial setup a bit harder.
implementing a basic token auth should not be very difficult for anyone
with some java knowledge. It would then be as simple as
- generating a random string that can be written in a HTTP header
- providing that string to the server through the config file
- sending the string in the Authorization header
x509 client certificate requires a full on private key infrastructure with
a certificate authority which is known by both parties. In my experience it
is used more to secure machine to machine communication (webservices) than
for requests operated by humans as configuring the clients to use the
correct certificates is usually quite painful/fragile. I haven't thought
too deeply about it but I guess it would suffer from more or less the same
issues as the JWT solutions while being even more complex to setup.
Any other scheme I can think of requires server side storage of the
credentials and thus much more work.
Jean
On Sun, Feb 16, 2025 at 10:53 PM cryptearth
<cryptea...@cryptearth.de.invalid> wrote:
Hey there everyone,
so I put together some lines and uploaded them onto my github:
https://github.com/n0xena/apache-james-webadmin
The basic gist: There's one certificate generator and two files to show
how to setup the server and client. It's pretty much the same code
already in place for the socketTLS and startTLS but with a trust root
and the clientAuth set.
As James already comes with BouncyCastle I reused it for loading the PEM
encode files - but this could be conde in some other way to keep it
vanilla java without any external lib dependencies.
Its sole security relies on the admin controls the client certificates
and hence the root private key should be kept offline. Also the
certificates lack a lot of usually common extensions like
authority/subject key information, crl/ocsp, policies and others. But
populating these extensions requires to provide additional services like
regular updated CRLs or online OCSP service.
As mentioned the certificate management can be done with openssl, but I
don't know how to do that properly.
Again: This is just a proposal of how to secure a service with standard
x509 certificates. But I see some token-based auth the proper solution.
So a proper example for how to setup/use JWT would be more useful as
it's already implemented.
I'll add some proper explanation/comments over the week.
Have a good one.
Matt
Am 14.02.25 um 11:37 schrieb Ilya Terskov:
Hi there Matt. Looking forward anything u doin :) i think u need use - So
long © as ur special word for something pretty hard and need a lot of
time
to make it work ^_^
пт, 14 февр. 2025 г., 12:05 cryptearth <cryptea...@cryptearth.de
.invalid>:
Well, a simple credential based auth like a password as the most common
and basic form of a challenge-response would work if the webadmin
wouldn't be a rest endpoint. But as it is and the way a rest api is
meant to be used this credential has to be give at each request. Fun
fact: it doesn'T really matter if this "one has to provide some
credential over and over again" is some password, some other kind of
token or even the rather expensive mutual tls. The point is rather a
rest api endpoint is really meant for such. A different approach could
be to convert it from a rest endpoint to something with a continous
connection like the keep-alive header in http to re-use one already
established connection for multiple requests instead of open a new
request for every resource.
The JWT is a good idea although it lacks some example how to set it up
(at least I wasn't able to figure it out) and maybe it could be
simplified to be just an arbitrary token instead of something that
requires cryptography. The idea should be, at least as the first step,
to put some kind of simple protection in place to close the
vulnerability of "it's an open unprotected admin control endpoint". And
if it's just some token set fixed in the config which has to be provided
along. Yes, someone may see this still as vulnerable - but as I
mentioned: when someone already has local access to your server to
extract that token from the config then you likely have way more serious
issues to deal with than someone abusing the james webadmin endpoint.
Anyway - I try to come up with some example over the weekend. Have to go
to work now.
So long.
Matt
Am 13.02.25 um 02:10 schrieb Ilya Terskov:
Hi guys, so if using lets encrypt certificate, anyone can get access?
What
about certificates with password? Client need to write correct one to
get
access? Also additional user/pass layer i think good thing ofc with
tls/ssl. Thanks for your hard work. I not developer and all i can help
u
with just testing and get logs :( sorry about that, i know i am
disturbing
you pretty much Matt and Benoit too.
чт, 13 февр. 2025 г., 07:57 cryptearth <cryptea...@cryptearth.de
.invalid>:
Hello Benoit,
I'm happy to provide something back to the James project.
Unfortunately
I read your reply too late to start work on it over the past weekend.
And currently I work long shifts due to high backlog that has to be
cleaned up. I try to tinker some lines together over the upcomming
weekend and provide them over on my github.
Long story short: Setting up your own PKI and some lines of Java to
setup mutual TLS is quite easy. James already comes with the required
BouncyCastle libs bcpkix, bcprov and bcutil to do so.
I have to stress: As by the standard any client certificate signed by
any of the specified root PKI will pass the verification - so using
Let's Encrypt is discouraged as ANY LE client cert will be valid. To
use
mutual TLS properly one pretty much has to setup thier own PKI to be
in
control of any certificates issued.
Also both Java SSE and BouncyCastle are able to perform basic validity
checks like CRL or OCSP but these has to be kept up along. As the RFC
only recommends these to have setup but not actually require them the
simplest setup is a root ca certificate and two leaf certificates, one
for the server and one for the client, without all the fancy stuff
like
AIA, CRL-dp or any of the other x.509 extensions.
This can also be done with a few simple openssl commands (and unless
you're a java dev with a jdk installed that's likely the better
solution) - but as I'm a hobbyist java dev I always did it this way
and
don't know the openssl commands. So someone with experience in both my
provide a "translation".
Anyway - I see how I have time and report back if I have some example
written down.
Have a good one.
Greetings,
Matt
Am 09.02.25 um 22:55 schrieb Benoit TELLIER:
Hi there
I had a private discussion couple of week ago with Jean HELOU who
complained of webadmin being hard top secure and hé proposer settings
up an
optional basic auth scheme, easier to use that the jwt bearer token.
Would this be helping?
Would this be something you would be willing to contribute, with
guidance?
Idem for repairing the TLS setup, or making it usable with pem
files...
--
Best regards,
Benoit TELLIER
General manager of Linagora VIETNAM.
Product owner for Team-Mail product.
Chairman of the Apache James project.
Mail: btell...@linagora.com
Tel: (0033) 6 77 26 04 58 (WhatsApp, Signal)
Le févr. 8, 2025 6:06 PM, de Cryptearth <cryptea...@cryptearth.de
.INVALID>Hi
Ilya,
for me in my very own personal opinion using RSA keys would be fine
already, or any other established public-key auth like SSH. But JWT
already is some sorts of this which just has to be implemented
correctly. I tried to look into it but honestly not really understood
it. So I guess if someone could give me just an example I likely
would
be able to figure it out on my own.
Another option I already use on other projects: mutual TLS.
It's easy to setup your own PKI and using client certificates for
both
authentication and identification is part of the TLS standard itself
and
works with established servers like apache httpd. Implementing it in
java is as easy as to set your own root-ca-cert as trustanchor when
creating the TLS server socket. The server then requests a client
certificate signed by the root-ca-cert (even works with intermediate
certs) during the handshake and if none is presented the connection
is
terminated. All the verification is done by the java SSE itself -
nothin
complicated to implement - just setup two certificates.
Should this be a (or THE) route to implement security on webadmin? I
don'T think so. It's an open admin control port and no matter if it
comes with some sort of auth or ident it should always be treated as
such - which means: only accessible local and protected by firewall
at
the very least. Yes, there still should be some security on top - but
it
often comes down to: if an attacker already got local access to your
server in most cases you lost already.
So, TLDR: For me if, for some reason, one need remote access to james
webadmin just use ssh tunneling like
ssh user@host -L8443:localhost:8443
and use the local 8443 and let ssh handle the auth and ident and
crypto
and all that stuff. We already have this tool at hand - and: "Don't
roll
your own crypto!".
Am 07.02.25 um 10:26 schrieb Ilya Terskov:
yeah guys i tried that in the end but one problem - if i have
forwards
to
other email - it need to delete also, same for aliases, so if doing
script
it need to do all that and recursively.
we sure need 3.9.0 with actions working :) about security on it i
think
we
need just RSA keys just like used in SSH and ofc encryption on this
chanel no plaintext for sure :)
---------------------------------------------------------------------
To unsubscribe, e-mail: server-user-unsubscr...@james.apache.org
For additional commands, e-mail: server-user-h...@james.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: server-user-unsubscr...@james.apache.org
For additional commands, e-mail: server-user-h...@james.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: server-user-unsubscr...@james.apache.org
For additional commands, e-mail: server-user-h...@james.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: server-user-unsubscr...@james.apache.org
For additional commands, e-mail: server-user-h...@james.apache.org