mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-11 21:10:29 +01:00
Enable single sign-on (SSO) support natively #5564
Closed
opened 2025-12-29 19:29:26 +01:00 by adam
·
13 comments
No Branch/Tag Specified
main
update-changelog-comments-docs
feature-removal-issue-type
20911-dropdown
20239-plugin-menu-classes-mutable-state
21097-graphql-id-lookups
feature
fix_module_substitution
20923-dcim-templates
20044-elevation-stuck-lightmode
feature-ip-prefix-link
v4.5-beta1-release
20068-import-moduletype-attrs
20766-fix-german-translation-code-literals
20378-del-script
7604-filter-modifiers-v3
circuit-swap
12318-case-insensitive-uniqueness
20637-improve-device-q-filter
20660-script-load
19724-graphql
20614-update-ruff
14884-script
02496-max-page
19720-macaddress-interface-generic-relation
19408-circuit-terminations-export-templates
20203-openapi-check
fix-19669-api-image-download
7604-filter-modifiers
19275-fixes-interface-bulk-edit
fix-17794-get_field_value_return_list
11507-show-aggregate-and-rir-on-api
9583-add_column_specific_search_field_to_tables
v4.5.0
v4.4.10
v4.4.9
v4.5.0-beta1
v4.4.8
v4.4.7
v4.4.6
v4.4.5
v4.4.4
v4.4.3
v4.4.2
v4.4.1
v4.4.0
v4.3.7
v4.4.0-beta1
v4.3.6
v4.3.5
v4.3.4
v4.3.3
v4.3.2
v4.3.1
v4.3.0
v4.2.9
v4.3.0-beta2
v4.2.8
v4.3.0-beta1
v4.2.7
v4.2.6
v4.2.5
v4.2.4
v4.2.3
v4.2.2
v4.2.1
v4.2.0
v4.1.11
v4.1.10
v4.1.9
v4.1.8
v4.2-beta1
v4.1.7
v4.1.6
v4.1.5
v4.1.4
v4.1.3
v4.1.2
v4.1.1
v4.1.0
v4.0.11
v4.0.10
v4.0.9
v4.1-beta1
v4.0.8
v4.0.7
v4.0.6
v4.0.5
v4.0.3
v4.0.2
v4.0.1
v4.0.0
v3.7.8
v3.7.7
v4.0-beta2
v3.7.6
v3.7.5
v4.0-beta1
v3.7.4
v3.7.3
v3.7.2
v3.7.1
v3.7.0
v3.6.9
v3.6.8
v3.6.7
v3.7-beta1
v3.6.6
v3.6.5
v3.6.4
v3.6.3
v3.6.2
v3.6.1
v3.6.0
v3.5.9
v3.6-beta2
v3.5.8
v3.6-beta1
v3.5.7
v3.5.6
v3.5.5
v3.5.4
v3.5.3
v3.5.2
v3.5.1
v3.5.0
v3.4.10
v3.4.9
v3.5-beta2
v3.4.8
v3.5-beta1
v3.4.7
v3.4.6
v3.4.5
v3.4.4
v3.4.3
v3.4.2
v3.4.1
v3.4.0
v3.3.10
v3.3.9
v3.4-beta1
v3.3.8
v3.3.7
v3.3.6
v3.3.5
v3.3.4
v3.3.3
v3.3.2
v3.3.1
v3.3.0
v3.2.9
v3.2.8
v3.3-beta2
v3.2.7
v3.3-beta1
v3.2.6
v3.2.5
v3.2.4
v3.2.3
v3.2.2
v3.2.1
v3.2.0
v3.1.11
v3.1.10
v3.2-beta2
v3.1.9
v3.2-beta1
v3.1.8
v3.1.7
v3.1.6
v3.1.5
v3.1.4
v3.1.3
v3.1.2
v3.1.1
v3.1.0
v3.0.12
v3.0.11
v3.0.10
v3.1-beta1
v3.0.9
v3.0.8
v3.0.7
v3.0.6
v3.0.5
v3.0.4
v3.0.3
v3.0.2
v3.0.1
v3.0.0
v2.11.12
v3.0-beta2
v2.11.11
v2.11.10
v3.0-beta1
v2.11.9
v2.11.8
v2.11.7
v2.11.6
v2.11.5
v2.11.4
v2.11.3
v2.11.2
v2.11.1
v2.11.0
v2.10.10
v2.10.9
v2.11-beta1
v2.10.8
v2.10.7
v2.10.6
v2.10.5
v2.10.4
v2.10.3
v2.10.2
v2.10.1
v2.10.0
v2.9.11
v2.10-beta2
v2.9.10
v2.10-beta1
v2.9.9
v2.9.8
v2.9.7
v2.9.6
v2.9.5
v2.9.4
v2.9.3
v2.9.2
v2.9.1
v2.9.0
v2.9-beta2
v2.8.9
v2.9-beta1
v2.8.8
v2.8.7
v2.8.6
v2.8.5
v2.8.4
v2.8.3
v2.8.2
v2.8.1
v2.8.0
v2.7.12
v2.7.11
v2.7.10
v2.7.9
v2.7.8
v2.7.7
v2.7.6
v2.7.5
v2.7.4
v2.7.3
v2.7.2
v2.7.1
v2.7.0
v2.6.12
v2.6.11
v2.6.10
v2.6.9
v2.7-beta1
Solcon-2020-01-06
v2.6.8
v2.6.7
v2.6.6
v2.6.5
v2.6.4
v2.6.3
v2.6.2
v2.6.1
v2.6.0
v2.5.13
v2.5.12
v2.6-beta1
v2.5.11
v2.5.10
v2.5.9
v2.5.8
v2.5.7
v2.5.6
v2.5.5
v2.5.4
v2.5.3
v2.5.2
v2.5.1
v2.5.0
v2.4.9
v2.5-beta2
v2.4.8
v2.5-beta1
v2.4.7
v2.4.6
v2.4.5
v2.4.4
v2.4.3
v2.4.2
v2.4.1
v2.4.0
v2.3.7
v2.4-beta1
v2.3.6
v2.3.5
v2.3.4
v2.3.3
v2.3.2
v2.3.1
v2.3.0
v2.2.10
v2.3-beta2
v2.2.9
v2.3-beta1
v2.2.8
v2.2.7
v2.2.6
v2.2.5
v2.2.4
v2.2.3
v2.2.2
v2.2.1
v2.2.0
v2.1.6
v2.2-beta2
v2.1.5
v2.2-beta1
v2.1.4
v2.1.3
v2.1.2
v2.1.1
v2.1.0
v2.0.10
v2.1-beta1
v2.0.9
v2.0.8
v2.0.7
v2.0.6
v2.0.5
v2.0.4
v2.0.3
v2.0.2
v2.0.1
v2.0.0
v2.0-beta3
v1.9.6
v1.9.5
v2.0-beta2
v1.9.4-r1
v1.9.3
v2.0-beta1
v1.9.2
v1.9.1
v1.9.0-r1
v1.8.4
v1.8.3
v1.8.2
v1.8.1
v1.8.0
v1.7.3
v1.7.2-r1
v1.7.1
v1.7.0
v1.6.3
v1.6.2-r1
v1.6.1-r1
1.6.1
v1.6.0
v1.5.2
v1.5.1
v1.5.0
v1.4.2
v1.4.1
v1.4.0
v1.3.2
v1.3.1
v1.3.0
v1.2.2
v1.2.1
v1.2.0
v1.1.0
v1.0.7-r1
v1.0.7
v1.0.6
v1.0.5
v1.0.4
v1.0.3-r1
v1.0.3
1.0.0
Labels
Clear labels
beta
breaking change
complexity: high
complexity: low
complexity: medium
needs milestone
netbox
pending closure
plugin candidate
pull-request
severity: high
severity: low
severity: medium
status: accepted
status: backlog
status: blocked
status: duplicate
status: needs owner
status: needs triage
status: revisions needed
status: under review
topic: GraphQL
topic: Internationalization
topic: OpenAPI
topic: UI/UX
topic: cabling
topic: event rules
topic: htmx navigation
topic: industrialization
topic: migrations
topic: plugins
topic: scripts
topic: templating
topic: testing
type: bug
type: deprecation
type: documentation
type: feature
type: housekeeping
type: translation
Mirrored from GitHub Pull Request
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/netbox#5564
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @jeremystretch on GitHub (Oct 27, 2021).
Originally assigned to: @jeremystretch on GitHub.
NetBox version
v3.0.8
Feature type
New functionality
Proposed functionality
This FR seeks to introduce built-in support for single sign-on authentication using
python-social-auth, and specificallysocial-app-django(formerlydjango-social-auth). This is a continuation of the discussion under #2328.Currently, NetBox defines two authentication backends:
This FR will allow administrators to either replace or supplement the default
REMOTE_AUTH_BACKENDwith one provided bypython-social-auth. More detail on the proposed implementation can be found in the project's documentation.I haven't dug into this much yet, so I'm not sure what sort of roadblocks we might run into. We'll also need to ensure to avoid any conflicts with NetBox's object-based permissions system, although those should be minor as that deals with authorization rather than authentication.
Use case
This will allow NetBox administrators to enable one or more of the supported authentication backends (e.g. Google, Okta, GitHub, etc.) for authenticating NetBox users, in addition to the local authentication and custom remote authentication options already provided.
Database changes
The Django app will install several models, but they will be managed outside of NetBox. I don't believe any database changes are necessary within NetBox itself.
External dependencies
social-auth-app-djangoandsocial-auth-corewill be introduced as required dependencies. Additional packages may be needed depending on the configured backend(s), however they should be optional.@nahun commented on GitHub (Oct 27, 2021):
This would be great to have built-in. I already patch in
python-social-authin my deployment like this: https://gist.github.com/nahun/5d4d715ca37a2465aaf59ab152413dc2The main features I would look for:
No database changes are needed in my use case.
@jeremystretch commented on GitHub (Oct 27, 2021):
Awesome, thank you @nahun!
@yrro commented on GitHub (Oct 28, 2021):
A comment from the PoV of someone who will use this to authenticate against his organization's Azure Active Directory once the code lands:
Whatever OpenID Connect implementation you choose, please make sure that it uses the tuple of (
iss,sub) claims to uniquely identify users, rather than any other claims such asemail!This is because user names change from time to time, and matching user records against the correct claim saves users a lot of time and effort when those renames happen.
Some docs for reference:
https://openid.net/specs/openid-connect-core-1_0.html#ClaimStability
and
https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#using-claims-to-reliably-identify-a-user-subject-and-object-id
Anyway - it's not quite as simple as using
subfor the username. Because then that horrible string that has no meaning to the user is displayed throught the user interface. For apps like NetBox that have an existing user model that expects a username, the right thing to do is use thepreferred_usernameclaim for the user-visible username, and add extra fields to the users table to storeissandsub(or munge them together into a single value if you don't want to rely on composite keys, though PostgreSQL supports them perfectly well AFAIK). These values are then only used for looking up a user record in the redirect handler in order to insert/update as appropriate.Also - a +1 for updating groups based on the
roleclaim during login. I can then offload all user role management to the IdP rather than doing it in NetBox itself. I am happy to try working on this if you want.@jeremystretch commented on GitHub (Oct 29, 2021):
Well, given that the necessary modifications to core seem fairly minor, maybe it makes sense to include
social-auth-app-djangoin the v3.1 beta. I suspect we'll need to do quite a lot of testing and make iterative improvements as we go. It might not be fully production-ready in the v3.1 release but it also shouldn't really interfere with anything.@yrro We're going to be constrained by the backends provided by
social-auth-app-django, which in your case seems like it would beAzureADOAuth2. I'm not familiar enough with this yet to say whether your concern will be addressed, but if not it should be fairly easy to write a custom backend that operates exactly as needed.@jeremystretch commented on GitHub (Oct 29, 2021):
Working off of the docs and @nahun's example I was able to get a bare minimum implementation of python-social-auth up and running pretty quickly in the
7649-social-authbranch. It's extremely bare bones at the moment, but should provide a sufficient test bed for additional work.@nahun commented on GitHub (Oct 31, 2021):
Thanks Jeremy! I got my use case working in the
7649-social-authbranch as a test.Here is what I put in
configuration.py:And then I still placed a
custom_pipeline.pyin the folder with the same contents of my previous example. I don't know whats best with the pipelines: have some built-in official way of supporting custom pipelines or leaving it up to the user like this.My only request is to set a "default" Auth Backend so that it doesn't load the
/loginpage, it would immediately redirect to that backend. My users never need to see the NetBox login page itself. You'll probably need to build some method of forcing a login page for a local account. I haven't needed that myself, but I could see that being a need for others.@jeremystretch commented on GitHub (Nov 1, 2021):
IMO it's best to leave it open to the user, much like we do with the
REMOTE_AUTH_BACKENDsetting. You're free to specify whatever you'd like, so long as it's been made accessible within NetBox' environment. Of course, it would make sense to include some commonly used functions out of the box, I just don't know what those are yet.We could expose Django's
LOGIN_URLsetting. Would that work? Or would you need some greater degree of flexibility to allow the actual URL to be inferred from the configured auth backend?@jeremystretch commented on GitHub (Nov 1, 2021):
I'm going to tag this for v3.1. We'll likely continue to improve the implementation but I think even the minimal implementation achieved thus far is valuable.
@nahun commented on GitHub (Nov 1, 2021):
My guess is my example of setting username and mapping roles to groups would be the most basic and common. Really is a guess though.
For me, exposing
LOGIN_URLis sufficient. The more user friendly way would be to infer the URL from the backend. Like choosing a default backend so that it changes theLOGIN_URLitself.@jeremystretch commented on GitHub (Nov 2, 2021):
I've gone ahead and merged the MVP implementation for this. I expect to continue work under the
featurebranch during the v3.1 beta period as we receive additional feedback.@l1bra2013 commented on GitHub (Nov 2, 2021):
Just wanted to add some feedback about this. Although adding the social-auth app works fine for frontend authentication, it doesn't provide a good mechanism for API auth. There is a mechanism provided by https://github.com/RealmTeam/django-rest-framework-social-oauth2, although the project appears dead
It may be best to adjust the netbox
configuration.pyto be more flexible in allowing the user to simply specify what, if any, authentication override they may want for both the frontend and backendFor example, if using Mozilla Django OIDC, that plugin provides the ability to enable both frontend and API auth overrides, but the following files need changing:
mozilla_django_oidctoINSTALLED_APPSurls.pylogin.htmlto include an OIDC login button, optionally remove built-in user auth, and optionally modify other templates as needed to adjust the logout buttonThese changes work with the existing REMOTE_AUTH_ variables, by specifying a Django compatible auth class (in this case mozilla OIDC)
I think that in the spirit of the REMOTE_AUTH mechanism, it would be better to allow the user to determine what auth mechanism works best for their use case, but provide some sort of mechanism for the user to make the necessary changes, outlined above and pretty much the same in the recently merged PR. If netbox incorporated some sort of improvements to allow for these changes as more of an addon/override rather than a modification to the netbox code, that may make everyone happy.
Then examples could be provided for common mechanisms such as social-auth, mozilla-oidc, ...
@marcus-crane commented on GitHub (Nov 9, 2021):
I guess I'll chime in with my hat as the maintainer of the somewhat spaghetti but still functional netbox-plugin-azuread that my previous employer and a few others have been using to authenticate into Netbox via Azure Active Directory.
First off, I'm really excited to see this functionality getting first class support. I'll be looking forward to the day when I can deprecate the plugin fully and point towards Netbox proper.
As far as functionality goes, I'm no Azure AD expert at all so the main things I would echo are what nahun already mentioned about attributes and mapping roles. In addition to that, it makes sense to filter roles too since it's a bit redundant importing potentially thousands of user roles when only a few are used. That said, I'm assuming you'd be mirroring Azure AD groups into Django land.
When it comes to UX, the main fiddly bits are login and redirect/reply URIs. I don't think the reply URIs matter so much (
plugins/azuread/complete/) in my case. For the login url, my plugin is often used in conjunction with nginx to just proxy pass over the top of/login/but of course, that's redundant when you control the source repo :)For this case, perhaps it makes sense to just surface n number of buttons in the login template that show up as users enable different auth backends instead of treating it too differently. I can see someone enabling a billion backends and then complaining when buttons slide off the page though haha.
Anyway, I haven't had a play with the beta just yet so I'll let you know if I have any feedback and I'm looking forward to seeing it progress!
@yrro commented on GitHub (Nov 9, 2021):
That depends on the token claims configured upon the Azure AD App Registration by the Azure AD Application Administrator.
The proper (dare I say "modern") way to do it is to define roles (e.g,, viewer, editor, admin, staff) on the App Registration, and then configure the mapping of users (or groups) to roles upon the corresponding Azure AD Enterprise Application (which is confusingly also often described as "the service principal" in various places).
As a result, the the app's ID token will include a
rolesclaim with just the application-specific roles configured.The other, legacy way of doing it is to configure the App Registration's ID Token to include a
groupsclaim, and then the Application Administrator has to decide which Azure AD groups should be included in thegroupsclaim. This has a number of shortcomings and basically only exists to aid in migrating legacy apps away from AD FS. These are described at https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-fed-group-claims if you want the gory details.TL;DR: define roles on the App Registration, determine who gets what roles on the Enterprise Application, and the
rolesclaim will include the assigned roles.On the application side, something has to consume the
rolesclaim of course. A typical Django app might set the user'sis_adminandis_stafffields based on the presence ofadminandstaffroles. Those two are easy. In NetBox's case, it might make sense to map other roles to the IDs of particular Permission objects, defined statically in the config file...