arangodb / arangodb

🥑 ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values. Build high performance applications using a convenient SQL-like query language or JavaScript extensions.
https://www.arangodb.com
Other
13.59k stars 837 forks source link

req.arangoUser is null in Foxx service #2382

Closed naumf closed 7 years ago

naumf commented 7 years ago

my environment running ArangoDB

I'm using the latest ArangoDB of the respective release series:

On this operating system:

Foxx

this is a web interface-related issue:

I'm using the web interface with this browser: running on this OS:

These are the steps to reproduce: 1) Created a database (koa_db) and new user (koa_user) with rw privileges granted to this db 2) Logged in with the new user account and selected the new database 3) Added a simple Foxx service and this is the middleware which always throws 401:

module.context.use(function (req, res, next) {
    console.log('auth_enabled: ', internal.authenticationEnabled());
    console.log('authorization_header: ', req.headers.authorization);
    console.log('arango_user: ', req.arangoUser);
    if (!req.arangoUser) {
        res.throw(401, 'Not authenticated with ArangoDB');
    }
    next();
});

4) I am using arangojs client driver to do the requests from a node.js app. Tried with basic auth and jwt bearer token also tried with root user. req.arangoUser is null with both auth types and for both users. It's also null when running it from the service's api docs found in the arango web interface. 5) Here are the logs:

- auth_enabled: true
- authorization_header: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTI1MjI5MDQsImlhdCI6MS40ODk5MzA5MDQxMjUyNzhlKzYsImlzcyI6ImFyYW5nb2RiIiwicHJlZmVycmVkX3VzZXJuYW1lIjoia29hX3VzZXIifQ==.HPhJeB6uu2wyrobzn6z7Jk5oK8YDI0JnhodowmWt22A=
- arango_user: null

6) Auth is fine for getting db, creating docs, running queries from client, it's not working only for foxx service

Is it a bug or I am doing something wrong or maybe I'm just misunderstanding the concept of ArangoDB auth and req.arangoUser?

Many thanks

pluma commented 7 years ago

The arangoUser will only be set if ArangoDB successfully authenticated the request with the given credentials. JWT bearer tokens are bound to a user. Users (and services) are always bound to a database. So a JWT token for the root user of the _system database might be different from the one for the root user of a different database.

Can you confirm the token/credentials are valid for a user of the database the service is mounted on?

pluma commented 7 years ago

Aside from the issue itself, keep in mind that when using ArangoDB users to handle authentication to your service the users will be able to use the same credentials for the system API should they be able to access those URLs -- so in addition to being able to make requests to your service they can perform arbitrary queries and create/drop collections and even execute arbitrary JavaScript.

So unless the service is intended to help administrating the database itself, it's probably a better idea to build your own user management: https://docs.arangodb.com/3.1/Manual/Foxx/Users.html

naumf commented 7 years ago

Can you confirm the token/credentials are valid for a user of the database the service is mounted on?

Yes, token with Bearer auth and credentials with Basic auth are valid for db.query, db.get etc on koa_db, only the Foxx service is the problem. The Foxx service is mounted to the same database. koa_db is the database, koa_user is the user, test service is mounted to koa_db.

Regarding the another comment user management will be done in Node.js with Koa based rest api. I'm planning to use the ArangoDB service as a stored procedure and it will be accessed only by the api server. Here is my approach:

Regarding the security as you mentioned in the above comment, is my approach ok? I don't want to do user management in both places (1 in Node.js api server and in in the ArangoDB service itself)

Thanks

naumf commented 7 years ago

Here are the logs when using basic auth:

- auth_enabled: true
- authorization_header: Basic a29hX3VzZXI6a29hMTIz
- arango_user: null
jsteemann commented 7 years ago

I think what's happening here is the that the server is running with (default) setting --server.authentication-system-only true. With this setting, whenever there is an access attempt to any ArangoDB API such as /_api/... or /_admin/..., the request must pass authentication. Unprivileged accesses will be rejected here. And privileged accesses will have passed the authentication procedure. However, accesses to other APIs (this includes all the user-defined Foxx APIs) will not require authentication with this setting. They will simply bypass authentication. This is intentional with this setting, as Foxx apps often have their own user authentication and use different users than those that are used for accessing the database APIs. Long story short: there will be no authentication for these accesses, so there is no authenticated user there. To turn authentication on for Foxx apps, the setting --server.authentication-system-only can be set to false. Then there will be authentication for any accesses to Foxx apps as well, and the arangoUser object will be populated.

pluma commented 7 years ago

@jsteemann that doesn't sound right. The /_admin routes also don't enforce authentication althought they do use (valid) auth credentials if present. Otherwise the web interface wouldn't be able to expose a graphical login at all (just like the /_api routes flat-out reject unauthenticated requests at the C++ level).

Unless of course we do special handling of /_admin to parse credentials if present but do nothing when they're invalid or omitted, which would be surprising. The expected (and documented) behaviour for non-/_api routes should be that credentials are always parsed if present but ignored if invalid or omitted, not just for /_admin. With server authentication disabled entirely I would be fine either way (i.e. credentials can be ignored completely or parsed if present) as long as it's consistent.

Could you or @m0ppers look into the C++ code dealing with the authentication and check whether there's anything special we do that might explain why /_admin behaves this way (i.e. differently from the native /_api routes) but other Foxx routes don't?

EDIT: Another explanation might be if server.authentication-system-only=false doesn't actually control access to services but merely populates the rawReq.user and leaves auth checking as an exercise to the developer -- which I would consider a bug.

EDIT2: Nope, server.authentication-system-only=false behaves exactly as expected: unauthenticated requests are completely rejected before they reach Foxx.

jsteemann commented 7 years ago

@pluma: /_api and /_admin all require authentication. Period.

jsteemann commented 7 years ago

@pluma: except /_admin/aardvark, that is... Otherwise it would indeed be impossible to serve the graphical login.

naumf commented 7 years ago

To turn authentication on for Foxx apps, the setting --server.authentication-system-only can be set to false

This solved the issue.

Many thanks

pluma commented 7 years ago

The setting only controls whether authentication is enforced for all Foxx services (rather than just the system services like the web admin interface). The behaviour as documented still wasn't available to non-system services, however:

  1. if a request contains valid ArangoDB credentials, req.arangoUser should ALWAYS be set to the corresponding ArangoDB username (e.g. "root"). (this didn't work)

  2. if a request contains invalid ArangoDB credentials or no credentials, req.arangoUser should be set to null but the request should still be passed to the Foxx service unless server.authentication-system-only is set to false. (this was already the case)

We've fixed this in the devel branch so the behaviour in 3.2 will be as implied by the documentation.

dothebart commented 7 years ago

3.2 alpha 4 containing this bugfix is available for download now.