rmountjoy92 / DashMachine

Another web application bookmark dashboard, with fun features.
GNU General Public License v3.0
1.24k stars 121 forks source link

Alternative Authentication Backends #7

Open rmountjoy92 opened 4 years ago

rmountjoy92 commented 4 years ago

This is fabulous Ross! Figure this may be further down the request list, but it would be awesome to integrate with OAUTH providers (KeyCloak, GitHub, etc) for authentication purposes.

dmigis commented 4 years ago

I second this, it would be nice to integrate with Nextcloud OAuth and be able to sync group membership between NC and DashMachine

ghost commented 4 years ago

Hi, It would be great to allow integration with LDAP too.

Any thoughts on this?

Thanks and regards

rmountjoy92 commented 4 years ago

To be totally honest, I don't even know where to start for this lol. I'm using flask login for the auth system.

dmigis commented 4 years ago

@rmountjoy92 If you are speaking about auth against OAuth2, look at this: https://flask-dance.readthedocs.io/en/latest/index.html In case of Nextcloud (shortly NC) Oauth2, you need to use custom provider (https://flask-dance.readthedocs.io/en/latest/providers.html#custom) and do the following:

  1. Read DashMachine (shortly DM) config file for:
    • Nextcloud instance URL
    • Nextcloud OAuth2 Client ID and Secret (generated once in NC Control panel)
  2. Substitute client_id and client_secret variables with Client ID and Secret from config file accordingly
    • base_url=NC instance URL from config
    • token_url=NC instance URL from config/apps/oauth2/api/v1/token
    • authorization_url=NC instance URL from config/apps/oauth2/authorize
  3. Then you'll get OAuth token, which will be in JSON form and will be stored in Flask session storage or using SQLAlchemy. You'll need to make a callback to DM and make an HTTP GET request to /ocs/v2.php/cloud/user?format=json with following header: headers = { "Accept": "application/json", "User-Agent": "DashMachine", "Authorization": "{} {}".format(token_type<get this from JSON>, access_token), } You'll get following JSON answer: {'ocs': {'meta': {'status': 'ok', 'statuscode': 200, 'message': 'OK'}, 'data': {'storageLocation': <redacted>, 'id': <redacted>, 'lastLogin': <redacted>, 'backend': 'Database', 'subadmin': [], 'quota': {'free': <redacted>, 'used': <redacted>, 'total': <redacted>, 'relative': <redacted>, 'quota': <redacted>}, 'email': None, 'phone': '', 'address': '', 'website': '', 'twitter': '', 'groups': [<redacted>], 'language': 'en', 'locale': '', 'backendCapabilities': {'setDisplayName': True, 'setPassword': True}, 'display-name': '<redacted>'}}}
  4. After you got JSON answer with user data, you need to extract following parameters and sync them with DashMachine DB:
    • ocs.data.id (username)
    • ocs.data.display-name (Full name)
    • ocs.data.groups (NC group membership)
    • ocs.data.language (Prefered language)
      6) Check, whether user is in NC "admin" group. If yes, add him to DashMachine admins. If he already DashMachine Admin, but not in NC "admin", then I prefer to delete from DashMachine admins. 7) Check, do NC groups exist in DM config file. Show the content only for groups, which both exist in DM and NC.

Thats how NC Oauth workflow for DM looks. I hope, it will help you in integrating OAuth (especially in conjuction with NC). If I'll have time, I will implement it

rmountjoy92 commented 4 years ago

Awesome write-up, next time I have some time, I will definitely play around with this. Thanks!

dmigis commented 4 years ago

Awesome write-up, next time I have some time, I will definitely play around with this. Thanks!

Thanks!

P. S. Almost forgot to attach some piece of docs, which will help you develop custom OAuth provider interface using Flask-dance: https://flask-dance.readthedocs.io/en/latest/api.html

Vad1mo commented 4 years ago

I would like to propose a solutions that doesn't blow up the code base with Identity Provider specific code.

The solution is to put an Auth proxy in front of DashMachine for users who look for advanced Identity Solutions. All popular web servers have a very extensive list of pluggable authentication modules. The auth proxy would then identify the user and could even do some authorization if needed. The information about the user (userId) or JWT would then be forwarded to DashMachine. DashMachine need just to read and parse the HTTP request headers to login or sign up and login the user.

The concept is called Reverse Proxy Auth or Proxy Auth.

In the Grafana docs one could read how this is done, its fairly simple but powerful. https://grafana.com/docs/grafana/latest/auth/auth-proxy/

Users who use nginx, apache, Caddy, Traefik could all use this concept. There is a whole ecosystem around that concept so its easy to fit everyones need.

dmigis commented 4 years ago

@Vad1mo The idea is very nice in my opinion, because it doesn't blow up code base (when I tried to implement NC Oauth, it was required to make some changes in SQLAlchemy Users models.py + add code for identity provider itself (and it is just for single provider) + stuck on frontend changes in order to provide user interface to toggle OAuth authorization). But there are some drawbacks: 1) It is not user-friendly (not all users are able to configure web server properly) + in some cases it is required to run separate OAuth proxy (like Vouch) and thus it will lead to increased resource consumption of the server (remember, that there are lots of people, who selfhost on RPi) 2) It doesn't fit my needs: I need OAuth (in my case via Nextcloud) and ability to configure user premissions (via group membership) according to NC JSON response. Maybe I don't understand, but I didn't find a way to do this on OAuth proxy side without rebuilding proxy or its Docker container or some provider-specific code in Dashmachine auth is required. If there is a way to bypass it, fell free to share.

@rmountjoy92 Whether Dashmachine will use Proxy Auth or Oauth via Flask, there is one problem, which I want to discuss: role and group management. For example, I assign user to multiple groups in NC in order to give access to Dokuwiki (if he is in wiki group), Jupyterhub (if he is in jupyter group) and so on. In the same time it allows me to manage access to files from these services. But, as I understand, user in Dashmachine can have only one role and this creates one problem: if both of NC groups are defined in DM config as roles, they are at the same level at role hierarchy and user is member of both of them, how to assign role to user during OAuth login? In order to avoid this, I suggest several solutions: 1) Ditch roles and let groups manage user permissions (and user can be member of multiple groups) 2) Let roles to manage access to settings and so on, and groups will manage access to cards. In this case user can have only one role (if he is NC admin, he'll be DM admin, others will get to user or public_user role), but be member of multiple groups. 3) Let user to assign role priority via DM config (but it is not flexible, as first 2 optiions)

This is the most important barrier on the way to implement NC OAuth support with user permission management via NC groups.

WolfeCub commented 4 years ago

Agreed.

The lack of backends wouldn't be so bad if you were able to disable the login page. That way we could stick our own auth in.

rhysjtevans commented 3 years ago

Any updates on this?