Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Mattia Rizzolo
nm.debian.org
Commits
33905a7f
Commit
33905a7f
authored
Apr 25, 2020
by
Enrico Zini
Browse files
Impersonate through a middleware. refs:
#12
parent
4c1bec3e
Changes
7
Hide whitespace changes
Inline
Side-by-side
backend/models.py
View file @
33905a7f
...
...
@@ -49,6 +49,7 @@ class PersonManager(BaseUserManager):
def
create_superuser
(
self
,
email
,
**
other_fields
):
other_fields
[
"is_superuser"
]
=
True
other_fields
[
"is_staff"
]
=
True
return
self
.
create_user
(
email
,
**
other_fields
)
def
get_or_none
(
self
,
*
args
,
**
kw
):
...
...
backend/unittest.py
View file @
33905a7f
...
...
@@ -103,7 +103,8 @@ class TestBase(nm2.lib.unittest.TestBase):
else
:
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
person
=
self
.
persons
[
person
]
if
isinstance
(
person
,
str
):
person
=
self
.
persons
[
person
]
if
person
is
not
None
:
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
client
.
visitor
=
person
...
...
@@ -128,7 +129,8 @@ class TestBase(nm2.lib.unittest.TestBase):
else
:
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
person
=
self
.
persons
[
person
]
if
isinstance
(
person
,
str
):
person
=
self
.
persons
[
person
]
if
person
is
not
None
:
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
client
.
visitor
=
person
...
...
impersonate/middleware.py
0 → 100644
View file @
33905a7f
from
__future__
import
annotations
from
django.core.exceptions
import
ImproperlyConfigured
from
django.contrib.auth
import
get_user_model
class
ImpersonateMiddleware
:
def
__init__
(
self
,
get_response
):
self
.
get_response
=
get_response
self
.
User
=
get_user_model
()
def
__call__
(
self
,
request
):
# AuthenticationMiddleware is required so that request.user exists.
if
not
hasattr
(
request
,
'user'
):
raise
ImproperlyConfigured
(
"The impersonator middleware requires the authentication middleware"
" to be installed. Edit your MIDDLEWARE setting to insert"
" 'django.contrib.auth.middleware.AuthenticationMiddleware'"
" before the ImpersonateMiddleware class."
)
if
request
.
user
.
is_authenticated
:
# Implement impersonation if requested in session
if
request
.
user
.
is_staff
:
pk
=
request
.
session
.
get
(
"impersonate"
,
None
)
if
pk
is
not
None
:
try
:
user
=
self
.
User
.
objects
.
get
(
pk
=
pk
)
except
self
.
User
.
DoesNotExist
:
user
=
None
if
user
is
not
None
:
request
.
impersonator
=
request
.
user
request
.
user
=
user
return
self
.
get_response
(
request
)
impersonate/tests.py
View file @
33905a7f
from
__future__
import
annotations
from
django.test
import
TestCase
from
django.urls
import
reverse
from
backend.unittest
import
PersonFixtureMixin
from
backend.unittest
import
TestBase
from
django.contrib.auth
import
get_user_model
class
TestPermissions
(
PersonFixtureMixin
,
TestCase
):
@
classmethod
def
__add_extra_tests__
(
cls
):
non_fd
=
[
"pending"
,
"dc"
,
"dc_ga"
,
"dm"
,
"dm_ga"
,
"dd_nu"
,
"dd_u"
,
"dd_e"
,
"dd_r"
,
"activeam"
,
"oldam"
]
fd
=
[
"fd"
,
"dam"
]
for
visitor
in
[
None
]
+
non_fd
:
for
visited
in
non_fd
+
fd
:
cls
.
_add_method
(
cls
.
_test_impersonate_fail
,
visitor
,
visited
)
class
TestPermissions
(
TestBase
,
TestCase
):
def
test_impersonate_staff
(
self
):
User
=
get_user_model
()
visitor
=
User
.
objects
.
create_superuser
(
email
=
"admin@example.org"
,
fullname
=
"Admin"
,
audit_skip
=
True
)
visited
=
User
.
objects
.
create_user
(
email
=
"user@example.org"
,
fullname
=
"User"
,
audit_skip
=
True
)
client
=
self
.
make_test_client
(
visitor
)
for
visitor
in
fd
:
for
visited
in
non_fd
+
fd
:
cls
.
_add_method
(
cls
.
_test_impersonate_success
,
visitor
,
visited
)
response
=
client
.
get
(
reverse
(
"impersonate:whoami"
))
self
.
assertJSONEqual
(
response
.
content
,
{
'impersonator'
:
None
,
'impersonator_desc'
:
None
,
'user'
:
visitor
.
pk
,
'user_desc'
:
str
(
visitor
),
})
def
_test_impersonate_success
(
self
,
visitor
,
visited
):
client
=
self
.
make_test_client
(
visitor
)
response
=
client
.
post
(
reverse
(
"impersonate"
),
data
=
{
"pk"
:
self
.
persons
[
visited
].
pk
,
"next"
:
"/"
})
response
=
client
.
post
(
reverse
(
"impersonate:impersonate"
),
data
=
{
"pk"
:
visited
.
pk
,
"next"
:
"/"
})
self
.
assertRedirectMatches
(
response
,
"^/$"
)
def
_test_impersonate_fail
(
self
,
visitor
,
visited
):
response
=
client
.
get
(
reverse
(
"impersonate:whoami"
))
self
.
assertJSONEqual
(
response
.
content
,
{
'impersonator'
:
visitor
.
pk
,
'impersonator_desc'
:
str
(
visitor
),
'user'
:
visited
.
pk
,
'user_desc'
:
str
(
visited
),
})
def
test_impersonate_user
(
self
):
User
=
get_user_model
()
visitor
=
User
.
objects
.
create_user
(
email
=
"user@example.org"
,
fullname
=
"User"
,
audit_skip
=
True
)
visited
=
User
.
objects
.
create_user
(
email
=
"user1@example.org"
,
fullname
=
"User1"
,
audit_skip
=
True
)
client
=
self
.
make_test_client
(
visitor
)
response
=
client
.
post
(
reverse
(
"impersonate"
),
data
=
{
"pk"
:
self
.
persons
[
visited
]
.
pk
})
response
=
client
.
post
(
reverse
(
"impersonate
:impersonate
"
),
data
=
{
"pk"
:
visited
.
pk
})
self
.
assertPermissionDenied
(
response
)
response
=
client
.
get
(
reverse
(
"impersonate:whoami"
))
self
.
assertJSONEqual
(
response
.
content
,
{
'impersonator'
:
None
,
'impersonator_desc'
:
None
,
'user'
:
visitor
.
pk
,
'user_desc'
:
str
(
visitor
),
})
def
test_impersonate_anonymous
(
self
):
User
=
get_user_model
()
visited
=
User
.
objects
.
create_user
(
email
=
"user@example.org"
,
fullname
=
"User"
,
audit_skip
=
True
)
client
=
self
.
make_test_client
(
None
)
response
=
client
.
post
(
reverse
(
"impersonate:impersonate"
),
data
=
{
"pk"
:
visited
.
pk
})
self
.
assertPermissionDenied
(
response
)
response
=
client
.
get
(
reverse
(
"impersonate:whoami"
))
self
.
assertJSONEqual
(
response
.
content
,
{
'impersonator'
:
None
,
'impersonator_desc'
:
None
,
'user'
:
None
,
'user_desc'
:
"AnonymousUser"
,
})
impersonate/urls.py
View file @
33905a7f
...
...
@@ -6,4 +6,5 @@ app_name = "impersonate"
urlpatterns
=
[
# Impersonate a user
path
(
'impersonate/'
,
views
.
Impersonate
.
as_view
(),
name
=
"impersonate"
),
path
(
'whoami/'
,
views
.
Whoami
.
as_view
(),
name
=
"whoami"
),
]
impersonate/views.py
View file @
33905a7f
...
...
@@ -5,6 +5,7 @@ from django.shortcuts import redirect
from
django.core.exceptions
import
PermissionDenied
from
django.contrib
import
messages
from
django.contrib.auth
import
get_user_model
from
django
import
http
class
Impersonate
(
View
):
...
...
@@ -13,7 +14,7 @@ class Impersonate(View):
effective_user
=
getattr
(
request
,
"impersonator"
,
None
)
if
effective_user
is
None
:
effective_user
=
request
.
user
if
not
effective_user
.
is_authenticated
or
not
effective_user
.
is_
admin
:
if
not
effective_user
.
is_authenticated
or
not
effective_user
.
is_
staff
:
raise
PermissionDenied
pk
=
request
.
POST
.
get
(
"pk"
)
if
pk
is
None
:
...
...
@@ -33,3 +34,14 @@ class Impersonate(View):
return
redirect
(
user
.
get_absolute_url
())
else
:
return
redirect
(
url
)
class
Whoami
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kw
):
impersonator
=
getattr
(
request
,
"impersonator"
,
None
)
return
http
.
JsonResponse
({
"user"
:
request
.
user
.
pk
,
"user_desc"
:
str
(
request
.
user
),
"impersonator"
:
None
if
impersonator
is
None
else
impersonator
.
pk
,
"impersonator_desc"
:
None
if
impersonator
is
None
else
str
(
impersonator
),
})
nm2/settings.py
View file @
33905a7f
...
...
@@ -88,6 +88,7 @@ MIDDLEWARE = [
'signon.middleware.SignonMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'impersonate.middleware.ImpersonateMiddleware'
,
]
AUTHENTICATION_BACKENDS
=
[
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment