orientdb: OrientDB authorization model can not be used as application level authorization

Such features as record level security encourage user to use OrientDB authorization as application level authorization. In other words, use OUser class as a main class for application user.

However there are some significant design issues in binary network protocol.

I suppose users would like to use approach similar to following

  • Application opens several sockets to database.
  • For each user connected to the application a db session is opened.
  • OPEN_DATABASE command is used to authorize user.
  • SessionID or similar entity is used as auth token.

Issues with concurrent requests

ODatabaseDocumentTx is not thread safe. And in binary network protocol each client session holds its instance of ODatabaseDocumentTx.

Thus session can not be used by several connections from different sockets because they can be handled in different server threads.

As a result we can not reuse session in different client threads.

This means that we have to open a new session for each user * each application thread. That leads to a need to reauthorize user in db for each thread. And as soon as user request can be handled by several application thread we have to store username and password at application layer.

Memory consumption

Having a thousands of active users may lead to thousands of opened connections in client connection manager. This could be memory consuming.

Possible memory leaks

If user is not logged out and socket was reused by other user, its session may remain in client connection manager forever. It won’t be closed automatically as soon as socket still alive and used by application to handle another user sessions.

Session Id shouldn’t be used as auth token

Session Id is serial, so it is not really safe to use it as a auth token.

No native way to make users rememberable

As soon as OrientDB supports only user/password authorization, “Remember me” feature could be implemented only by workarounds.

Automatic shutdown of session

Automatic shutdown of sessions that associated to broken connections are not designed for sessions that could be used by several connections.

So some session that is closed in such way may still be used by some other thread.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 73 (58 by maintainers)

Commits related to this issue

Most upvoted comments

@lvca I’ve put together a working implementation for token based authentication in orientdb. It isn’t perfect and requires some work to ensure proper security. However, I wanted to share with you so you could, if you wanted, test out whether this type of mechanism is appropriate for OrientDb.

All my changes are in my local repo: https://github.com/emrul/orientdb/commit/c15c979331767e897ecc489d3c390a61766c7b51

Obtaining a token

There is a new endpoint /token/<db_name> that will return an authentication token. In the example below there is a database named ‘TestTokenAuth’ with user ‘emrul@emrul.com’ and password ‘password’: The request parameters conform to the OAuth2 specification

curl --data "grant_type=password&username=emrul@emrul.com&password=password" http://localhost:2480/token/TestTokenAuth

This returns a JSON structure including the access_token and expires_in information. This is consistent with the OAuth2 specification but not complete:

{"@type":"d","@version":0,"access_token":"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyUmlkIjoiIzU6MyIsImV4cCI6MTQxMDgxOTE5NiwiZGF0YWJhc2VOYW1lIjoiVGVzdFRva2VuQXV0aCIsInN1YiI6ImVtcnVsQGVtcnVsLmNvbSIsImF1ZCI6Ik9yaWVudERiIiwiaXNzIjoiT3JpZW50RGIiLCJqdGkiOiI4N2YxZjIzNy1jMjhmLTRjMjctOWM0Yy05MDQ1MjgyMjgwYTEiLCJpYXQiOjE0MTA4MTkxODZ9.GD2r5Hf1hXSE_0R4BOMjfeZ8y_kBS2ysZvngAPTjjN8","expires_in":10000}

You can copy & paste the access token over at jwt.io, it looks like this:

{
  "userRid": "#5:3",
  "exp": 1410819196,
  "databaseName": "TestTokenAuth",
  "sub": "emrul@emrul.com",
  "aud": "OrientDb",
  "iss": "OrientDb",
  "jti": "87f1f237-c28f-4c27-9c4c-9045282280a1",
  "iat": 1410819186
}

The access token isn’t as I would prefer for a full implementation but contains the minimum needed to demonstrate the functionality.

Using a token for authentication

You pass the token as an bearer token in the Authorisation header. For example:

curl --header "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyUmlkIjoiIzU6MyIsImV4cCI6MTQxMDgxNzUxOCwiZGF0YWJhc2VOYW1lIjoiVGVzdFRva2VuQXV0aCIsInN1YiI6ImVtcnVsQGVtcnVsLmNvbSIsImF1ZCI6Ik9yaWVudERiIiwiaXNzIjoiT3JpZW50RGIiLCJqdGkiOiI2YWIzOTJlNy04ZWEzLTRmZmItYjhmMS1lZTlmMTVmYjY5ZDkiLCJpYXQiOjE0MTA4MTc1MDh9.LAT7MHlhihMkKwC_9dM1r3HFAfkj4BPngXzIEVxTlUg" "http://localhost:2480/query/TestTokenAuth/sql/select%20*%20from%20AClass"

Current implementation notes

  • The signing key is currently stored in the orientdb-server-config.xml as a Base64 encoded property named ‘oauth2.secretkey’ - like the root password, this would need to be changed for each implementation but a better approach would be to manage these keys in the database (perhaps on a per-database level). In my implementation the secret key has been set to ‘tokenkey’
  • Signature verification is currently performed twice (once in OSecurityShared and once in OServerCommandAuthenticatedDbAbstract) - this will need to be changed.
  • OSecurityShared has a new getUser method that loads the user directly by rid when authenticating by token - maybe this is a little faster than authentication by username.
  • The current implementation does not disable HTTP Basic auth (all of that code is still there and should work as it did before)
  • Expiry time is hard-coded (10 minutes). This should be configurable
  • I used Nimbus-JWT but I think it would be better to have our own token signing/verification classes rather than rely on this dependency.
  • No tests 😦

Summary

  • OrientDb is now an OAuth2 resource server. With a little more work OrientDb can be a full OAuth2 provider.
  • It is possible to enable Single-sign-on type systems because the token does not store or require the user password. To do this we would support ‘grant_types’ other than password.
  • We could make user of the OAuth2 ‘scopes’ field to store a list of roles. I believe this would get us to the externally managed accounts that @rajohn96 mentioned.

Any thoughts are welcome.