diff --git a/base_requirements.txt b/base_requirements.txt index 11ddac634..7295607f3 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -102,6 +102,14 @@ PyYAML # https://github.com/andymccurdy/redis-py redis +# Social authentication framework +# https://github.com/python-social-auth/social-core +social-auth-core[all] + +# Django app for social-auth-core +# https://github.com/python-social-auth/social-app-django +social-auth-app-django + # SVG image rendering (used for rack elevations) # https://github.com/mozman/svgwrite svgwrite diff --git a/docs/administration/authentication.md b/docs/administration/authentication.md new file mode 100644 index 000000000..31983be0b --- /dev/null +++ b/docs/administration/authentication.md @@ -0,0 +1,37 @@ +# Authentication + +## Local Authentication + +Local user accounts and groups can be created in NetBox under the "Authentication and Authorization" section of the administrative user interface. This interface is available only to users with the "staff" permission enabled. + +At a minimum, each user account must have a username and password set. User accounts may also denote a first name, last name, and email address. [Permissions](./permissions.md) may also be assigned to users and/or groups within the admin UI. + +## Remote Authentication + +NetBox may be configured to provide user authenticate via a remote backend in addition to local authentication. This is done by setting the `REMOTE_AUTH_BACKEND` configuration parameter to a suitable backend class. NetBox provides several options for remote authentication. + +### LDAP Authentication + +```python +REMOTE_AUTH_BACKEND = 'netbox.authentication.LDAPBackend' +``` + +NetBox includes an authentication backend which supports LDAP. See the [LDAP installation docs](../installation/6-ldap.md) for more detail about this backend. + +### HTTP Header Authentication + +```python +REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend' +``` + +Another option for remote authentication in NetBox is to enable HTTP header-based user assignment. The front end HTTP server (e.g. nginx or Apache) performs client authentication as a process external to NetBox, and passes information about the authenticated user via HTTP headers. By default, the user is assigned via the `REMOTE_USER` header, but this can be customized via the `REMOTE_AUTH_HEADER` configuration parameter. + +### Single Sign-On (SSO) + +```python +REMOTE_AUTH_BACKEND = 'social_core.backends.google.GoogleOAuth2' +``` + +NetBox supports single sign-on authentication via the [python-social-auth](https://github.com/python-social-auth) library. To enable SSO, specify the path to the desired authentication backend within the `social_core` Python package. Please see the complete list of [supported authentication backends](https://github.com/python-social-auth/social-core/tree/master/social_core/backends) for the available options. + +Most remote authentication backends require some additional configuration through settings prefixed with `SOCIAL_AUTH_`. These will be automatically imported from NetBox's `configuration.py` file. Additionally, the [authentication pipeline](https://python-social-auth.readthedocs.io/en/latest/pipeline.html) can be customized via the `SOCIAL_AUTH_PIPELINE` parameter. diff --git a/docs/administration/permissions.md b/docs/administration/permissions.md index 97b691c1d..f859266af 100644 --- a/docs/administration/permissions.md +++ b/docs/administration/permissions.md @@ -1,6 +1,6 @@ # Permissions -NetBox v2.9 introduced a new object-based permissions framework, which replace's Django's built-in permissions model. Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type. For example, it is possible to grant a user permission to view only sites within a particular region, or to modify only VLANs with a numeric ID within a certain range. +NetBox v2.9 introduced a new object-based permissions framework, which replaces Django's built-in permissions model. Object-based permissions enable an administrator to grant users or groups the ability to perform an action on arbitrary subsets of objects in NetBox, rather than all objects of a certain type. For example, it is possible to grant a user permission to view only sites within a particular region, or to modify only VLANs with a numeric ID within a certain range. {!models/users/objectpermission.md!} diff --git a/docs/release-notes/version-3.1.md b/docs/release-notes/version-3.1.md index d53f677d9..ff615a92b 100644 --- a/docs/release-notes/version-3.1.md +++ b/docs/release-notes/version-3.1.md @@ -57,6 +57,10 @@ A `bridge` field has been added to the interface model for devices and virtual m Multiple interfaces can be bridged to a single virtual interface to effect a bridge group. Alternatively, two physical interfaces can be bridged to one another, to effect an internal cross-connect. +#### Single Sign-On (SSO) Authentication ([#7649](https://github.com/netbox-community/netbox/issues/7649)) + +Support for single sign-on (SSO) authentication has been added via the [python-social-auth](https://github.com/python-social-auth) library. NetBox administrators can configure one of the [supported authentication backends](https://python-social-auth.readthedocs.io/en/latest/intro.html#auth-providers) to enable SSO authentication for users. + ### Enhancements * [#1337](https://github.com/netbox-community/netbox/issues/1337) - Add WWN field to interfaces diff --git a/mkdocs.yml b/mkdocs.yml index 52efdd656..84a7d1033 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - Using Plugins: 'plugins/index.md' - Developing Plugins: 'plugins/development.md' - Administration: + - Authentication: 'administration/authentication.md' - Permissions: 'administration/permissions.md' - Housekeeping: 'administration/housekeeping.md' - Replicating NetBox: 'administration/replicating-netbox.md' diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py index 8d03c6aee..959b6b525 100644 --- a/netbox/netbox/middleware.py +++ b/netbox/netbox/middleware.py @@ -8,7 +8,6 @@ from django.contrib import auth from django.core.exceptions import ImproperlyConfigured from django.db import ProgrammingError from django.http import Http404, HttpResponseRedirect -from django.urls import reverse from extras.context_managers import change_logging from netbox.config import clear_config @@ -20,23 +19,15 @@ class LoginRequiredMiddleware: """ If LOGIN_REQUIRED is True, redirect all non-authenticated users to the login page. """ - def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # Redirect unauthenticated requests (except those exempted) to the login page if LOGIN_REQUIRED is true if settings.LOGIN_REQUIRED and not request.user.is_authenticated: - # Determine exempt paths - exempt_paths = [ - reverse('api-root'), - reverse('graphql'), - ] - if settings.METRICS_ENABLED: - exempt_paths.append(reverse('prometheus-django-metrics')) # Redirect unauthenticated requests - if not request.path_info.startswith(tuple(exempt_paths)) and request.path_info != settings.LOGIN_URL: + if not request.path_info.startswith(settings.EXEMPT_PATHS): login_url = f'{settings.LOGIN_URL}?next={parse.quote(request.get_full_path_info())}' return HttpResponseRedirect(login_url) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 45475ef9a..6efd4d375 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -305,6 +305,7 @@ INSTALLED_APPS = [ 'graphene_django', 'mptt', 'rest_framework', + 'social_django', 'taggit', 'timezone_field', 'circuits', @@ -400,7 +401,8 @@ MESSAGE_TAGS = { } # Authentication URLs -LOGIN_URL = '/{}login/'.format(BASE_PATH) +LOGIN_URL = f'/{BASE_PATH}login/' +LOGIN_REDIRECT_URL = f'/{BASE_PATH}' CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS @@ -414,6 +416,27 @@ EXEMPT_EXCLUDE_MODELS = ( ('users', 'objectpermission'), ) +# All URLs starting with a string listed here are exempt from login enforcement +EXEMPT_PATHS = ( + f'/{BASE_PATH}api/', + f'/{BASE_PATH}graphql/', + f'/{BASE_PATH}login/', + f'/{BASE_PATH}oauth/', + f'/{BASE_PATH}metrics/', +) + + +# +# Django social auth +# + +# Load all SOCIAL_AUTH_* settings from the user configuration +for param in dir(configuration): + if param.startswith('SOCIAL_AUTH_'): + globals()[param] = getattr(configuration, param) + +SOCIAL_AUTH_JSONFIELD_ENABLED = True + # # Django Prometheus diff --git a/netbox/netbox/urls.py b/netbox/netbox/urls.py index 4e0a2e2c6..e76efe0fe 100644 --- a/netbox/netbox/urls.py +++ b/netbox/netbox/urls.py @@ -39,6 +39,7 @@ _patterns = [ # Login/logout path('login/', LoginView.as_view(), name='login'), path('logout/', LogoutView.as_view(), name='logout'), + path('oauth/', include('social_django.urls', namespace='social')), # Apps path('circuits/', include('circuits.urls')), diff --git a/netbox/templates/login.html b/netbox/templates/login.html index a01d75422..b7f466c16 100644 --- a/netbox/templates/login.html +++ b/netbox/templates/login.html @@ -39,6 +39,14 @@ + {# TODO: Improve the design & layout #} + {% if auth_backends %} +