django-centralauth

Latest Version Coverage Status Documentation Status https://travis-ci.org/moccu/django-centralauth.svg?branch=master

django-centralauth solves the problem of managing user access and permissions from multiple projects in one central place.

Features

  • based on OAuth2 standard.
  • provider app to set up your own user-management application.
  • client app for delegating authentication and permissions management to provider.

Requirements

django-centralauth supports Python 3 only and requires at least Django 1.11 and django-oauth-toolkit.

Prepare for development

A Python 3.6 interpreter is required in addition to pipenv.

$ pipenv install --python 3.6 --dev
$ pipenv shell
$ pip install -e .

Now you’re ready to run the tests:

$ pipenv run py.test

Resources

Contents:

Installation

  • Install with pip:

    pip install django-centralauth
    

Provider side

You need to update some of your Django settings.

  • Your INSTALLED_APPS setting:

    INSTALLED_APPS = (
        # ...
        'oauth2_provider',
        'centralauth.provider',
    )
    
  • Your MIDDLEWARE setting:

    MIDDLEWARE = [
        'oauth2_provider.middleware.OAuth2TokenMiddleware',
        # ...
    ]
    
  • Your AUTHENTICATION_BACKENDS setting:

    AUTHENTICATION_BACKENDS = (
        'oauth2_provider.backends.OAuth2Backend',
        # ...
    )
    
  • Add the following settings in addition:

    OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'oauth2_provider.AccessToken'
    OAUTH2_PROVIDER_APPLICATION_MODEL = 'provider.Application'
    
  • Configure the OAuth2 provider backend class:

    OAUTH2_PROVIDER = {
        'OAUTH2_BACKEND_CLASS': 'centralauth.provider.oauth2_backends.CentralauthOAuthBackend',
    }
    

If you want to re-validate the access more often, you might redurce the lifetime of the generated access tokens:

OAUTH2_PROVIDER = {
    # ...
    'ACCESS_TOKEN_EXPIRE_SECONDS': 5 * 60,
}

After you updated your settings, add the centralauth.provider urls to your url configuration:

urlpatterns = [
    # ...
    path('provider/', include('centralauth.provider.urls'))
]

Note

Make sure that you configure a sane LOGIN_URL. django-oauth-toolkit will redirect users to this url to ensure the requesting user is logged in.

Client side

You need to update some of your Django settings.

  • Your INSTALLED_APPS setting:

    INSTALLED_APPS = (
        # ...
        'centralauth.client',
    )
    
  • Your AUTHENTICATION_BACKENDS setting:

    # Disable regular logins using local users and enforce centralauth logins.
    AUTHENTICATION_BACKENDS = (
        'centralauth.client.backends.OAuthBackend'
    )
    
  • Add the following settings in addition:

    # The full uri to the provider side urls.
    CENTRALAUTH_PROVIDER_URL = 'http://localhost:8000/provider'
    
    # The application credentials generated on the provider side using the Django admin.
    CENTRALAUTH_CLIENT_ID = 'ADD-YOUR-CLIENT-ID'
    CENTRALAUTH_CLIENT_SECRET = 'ADD-YOUR-CLIENT-SECRET'
    

After you updated your settings, add the centralauth.client urls to your url configuration:

urlpatterns = [
    # ...
    path('centralauth/', include('centralauth.client.urls'))
]

Note

Centralauth provides an option to hijack the admin login interface to make sure that the users go through the Centralauth oauth login flow.

You might set CENTRALAUTH_CUSTOM_LOGIN_TEMPLATE to True or provide a Django template path to your custom template.

Changelog

1.2.0 (2019-02-22)

  • django-centralauth now depends on requests-oauthlib >= 1.2.0 and therefore oauthlib >= 3.0
  • Fixed some race conditions in middleware (when tokens are refreshed twice)

1.1.2 (2019-02-12)

  • Fix bug in get_or_create of permission sync api endpoint

1.1.1 (2019-01-10)

  • Fix permissions sync - remove deleted permissions

1.1.0 (2018-11-26)

  • Improve permission updates on user sync (don’t use clear, just merge source and target set)

1.0.0 (2018-11-22)

  • Initial release of django-centralauth

Api documentation:

API Reference

centralauth package

Subpackages
centralauth.client package
Submodules
centralauth.client.apps module
class centralauth.client.apps.ClientConfig(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

name = 'centralauth.client'[source]
ready()[source]

Override this method in subclasses to run code when Django starts.

centralauth.client.backends module
class centralauth.client.backends.OAuthBackend[source]

Bases: django.contrib.auth.backends.ModelBackend

Authenticate user with OAuth access token.

authenticate(request, token)[source]
get_user(user_id)[source]
centralauth.client.constants module
centralauth.client.constants.provider_url()[source]
centralauth.client.middleware module
class centralauth.client.middleware.CentralAuthSyncMiddleware(get_response=None)[source]

Bases: django.utils.deprecation.MiddlewareMixin

process_request(request, retries=0)[source]
centralauth.client.services module
centralauth.client.services.serialize_perm(perm)[source]

Serialize given permission object.

Returns:keys: app_lable, codename, repr.
Return type:dict
centralauth.client.services.register_perms()[source]

Register permissions available in the project to the provider.

centralauth.client.services.oauth2_client(token, session=None)[source]
centralauth.client.services.save_token(session, token)[source]
centralauth.client.services.load_token(session)[source]
centralauth.client.services.sync_user(user, client)[source]
centralauth.client.services.user_details(client)[source]
centralauth.client.services.update_user(user, **kwargs)[source]

Update user attributes and permissions

centralauth.client.urls module
centralauth.client.views module
centralauth.client.views.get_oauth_redirect_url(request, next_url=None)[source]
class centralauth.client.views.LoginView(**kwargs)[source]

Bases: django.views.generic.base.View

Request authorization code from provider.

Set next url in session. Build authorization code request and redirect to provider server.

get(*args, **kwargs)[source]
class centralauth.client.views.CallbackView(**kwargs)[source]

Bases: django.views.generic.base.View

Exchange authorization code for access token and authenticate user.

Authenticate user with access token. Redirect to next_url or admin page.

get(*args, **kwargs)[source]
centralauth.provider package
Submodules
centralauth.provider.admin module
class centralauth.provider.admin.ApplicationPermissionGroupAdminForm(*args, **kwargs)[source]

Bases: django.forms.models.ModelForm

class Meta[source]

Bases: object

widgets = {'permissions': <django.contrib.admin.widgets.FilteredSelectMultiple object>}[source]
base_fields = {'users': <django.forms.models.ModelMultipleChoiceField object>}[source]
declared_fields = {'users': <django.forms.models.ModelMultipleChoiceField object>}[source]
media[source]
class centralauth.provider.admin.ApplicationPermissionGroupAdmin(model, admin_site)[source]

Bases: django.contrib.admin.options.ModelAdmin

list_display = ('name', 'application')[source]
list_filter = ('application',)[source]
search_fields = ('name', 'applicationuser__user__username')[source]
form[source]

alias of ApplicationPermissionGroupAdminForm

fields = ('name', 'application')[source]
get_fields(request, obj=None)[source]

Hook for specifying fields.

get_readonly_fields(request, obj=None)[source]

Hook for specifying custom readonly fields.

get_inline_instances(request, obj=None)[source]

Given the HttpRequest, the parent ModelForm instance, the list of inline formsets and a boolean value based on whether the parent is being added or changed, save the related objects to the database. Note that at this point save_form() and save_model() have already been called.

media[source]
class centralauth.provider.admin.ApplicationUserAdminForm(*args, **kwargs)[source]

Bases: django.forms.models.ModelForm

base_fields = {}[source]
declared_fields = {}[source]
media[source]
class centralauth.provider.admin.ApplicationUserAdmin(model, admin_site)[source]

Bases: django.contrib.admin.options.ModelAdmin

list_display = ('user', 'application')[source]
list_filter = ('application',)[source]
search_fields = ('user__username',)[source]
form[source]

alias of ApplicationUserAdminForm

fields = ('user', 'application', 'is_superuser', 'is_staff', 'is_active')[source]
get_fields(request, obj=None)[source]

Hook for specifying fields.

get_readonly_fields(request, obj=None)[source]

Hook for specifying custom readonly fields.

media[source]
class centralauth.provider.admin.ApplicationUserInlineFormset(data=None, files=None, instance=None, save_as_new=False, prefix=None, queryset=None, **kwargs)[source]

Bases: django.forms.models.BaseInlineFormSet

get_form_kwargs(index)[source]

Return additional keyword arguments for each individual formset form.

index will be None if the form being constructed is a new empty form.

class centralauth.provider.admin.ApplicationUserInlineForm(*args, **kwargs)[source]

Bases: django.forms.models.ModelForm

base_fields = {}[source]
declared_fields = {}[source]
media[source]
class centralauth.provider.admin.ApplicationUserInline(parent_model, admin_site)[source]

Bases: django.contrib.admin.options.TabularInline

model[source]

alias of centralauth.provider.models.ApplicationUser

formset[source]

alias of ApplicationUserInlineFormset

form[source]

alias of ApplicationUserInlineForm

exclude = ('permissions',)[source]
extra = 0[source]
media[source]
class centralauth.provider.admin.ApplicationAdminForm(*args, **kwargs)[source]

Bases: django.forms.models.ModelForm

base_fields = {}[source]
declared_fields = {}[source]
media[source]
class centralauth.provider.admin.ApplicationAdmin(model, admin_site)[source]

Bases: django.contrib.admin.options.ModelAdmin

list_display = ('name', 'redirect_uris')[source]
form[source]

alias of ApplicationAdminForm

fields = ('name', 'client_id', 'client_secret', 'redirect_uris')[source]
inlines = [<class 'centralauth.provider.admin.ApplicationUserInline'>][source]
get_inline_instances(request, obj=None)[source]
media[source]
centralauth.provider.apps module
class centralauth.provider.apps.ProviderConfig(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

name = 'centralauth.provider'[source]
centralauth.provider.models module
class centralauth.provider.models.Application(*args, **kwargs)[source]

Bases: oauth2_provider.models.AbstractApplication

Centralauth custom application model.

save(*args, **kwargs)[source]

Save the current instance. Override this in a subclass if you want to control the saving process.

The ‘force_insert’ and ‘force_update’ parameters can be used to insist that the “save” must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

exception DoesNotExist[source]

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned[source]

Bases: django.core.exceptions.MultipleObjectsReturned

accesstoken_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

applicationpermission_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

applicationpermissiongroup_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

applicationuser_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

get_algorithm_display(*, field=<django.db.models.fields.CharField: algorithm>)[source]
get_authorization_grant_type_display(*, field=<django.db.models.fields.CharField: authorization_grant_type>)[source]
get_client_type_display(*, field=<django.db.models.fields.CharField: client_type>)[source]
get_next_by_created(*, field=<django.db.models.fields.DateTimeField: created>, is_next=True, **kwargs)[source]
get_next_by_updated(*, field=<django.db.models.fields.DateTimeField: updated>, is_next=True, **kwargs)[source]
get_previous_by_created(*, field=<django.db.models.fields.DateTimeField: created>, is_next=False, **kwargs)[source]
get_previous_by_updated(*, field=<django.db.models.fields.DateTimeField: updated>, is_next=False, **kwargs)[source]
grant_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

idtoken_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

objects = <django.db.models.manager.Manager object>[source]
refreshtoken_set[source]

Accessor to the related objects manager on the reverse side of a many-to-one relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Parent.children is a ReverseManyToOneDescriptor instance.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

user[source]

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

class centralauth.provider.models.ApplicationPermission(*args, **kwargs)[source]

Bases: django.db.models.base.Model

Model for holding all permissions available for application.

application[source]

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

repr[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

codename[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

app_label[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

date_created[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

exception DoesNotExist[source]

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned[source]

Bases: django.core.exceptions.MultipleObjectsReturned

application_id[source]
applicationpermissiongroup_set[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

applicationuser_set[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

get_next_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=True, **kwargs)[source]
get_previous_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=False, **kwargs)[source]
id[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>[source]
class centralauth.provider.models.ApplicationPermissionGroup(*args, **kwargs)[source]

Bases: django.db.models.base.Model

Model for for managing groups of permissions.

Permission groups are not synced with client Group objects. In client all permissions are handled on Permission object level.

name[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

application[source]

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

permissions[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

date_created[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

exception DoesNotExist[source]

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned[source]

Bases: django.core.exceptions.MultipleObjectsReturned

application_id[source]
applicationuser_set[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

get_next_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=True, **kwargs)[source]
get_previous_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=False, **kwargs)[source]
id[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>[source]
class centralauth.provider.models.ApplicationUser(*args, **kwargs)[source]

Bases: django.db.models.base.Model

Model for managing user permissions within application.

user[source]

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

application[source]

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example:

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

is_superuser[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_staff[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

is_active[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

permissions[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

groups[source]

Accessor to the related objects manager on the forward and reverse sides of a many-to-many relation.

In the example:

class Pizza(Model):
    toppings = ManyToManyField(Topping, related_name='pizzas')

Pizza.toppings and Topping.pizzas are ManyToManyDescriptor instances.

Most of the implementation is delegated to a dynamically defined manager class built by create_forward_many_to_many_manager() defined below.

date_created[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

get_permissions()[source]

Combine all user permissions.

Returns:list of ids of all user permissions.
Return type:list
exception DoesNotExist[source]

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned[source]

Bases: django.core.exceptions.MultipleObjectsReturned

application_id[source]
get_next_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=True, **kwargs)[source]
get_previous_by_date_created(*, field=<django.db.models.fields.DateTimeField: date_created>, is_next=False, **kwargs)[source]
id[source]

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>[source]
user_id[source]
centralauth.provider.oauth_urls module
centralauth.provider.urls module
centralauth.provider.urls.path(route, view, kwargs=None, name=None, *, Pattern=<class 'django.urls.resolvers.RoutePattern'>)[source]
centralauth.provider.views module
class centralauth.provider.views.UserEndpoint(**kwargs)[source]

Bases: oauth2_provider.views.generic.ProtectedResourceView

Endpoint for accessing user data.

This endpoint can be accessed only with valid access token in header.

get(request, *args, **kwargs)[source]
class centralauth.provider.views.PermsEndpoint(**kwargs)[source]

Bases: django.views.generic.base.View

dispatch(request, *args, **kwargs)[source]
post(request, *args, **kwargs)[source]

Indices and tables