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
Show whitespace changes
Inline
Side-by-side
backend/models.py
View file @
33905a7f
...
@@ -49,6 +49,7 @@ class PersonManager(BaseUserManager):
...
@@ -49,6 +49,7 @@ class PersonManager(BaseUserManager):
def
create_superuser
(
self
,
email
,
**
other_fields
):
def
create_superuser
(
self
,
email
,
**
other_fields
):
other_fields
[
"is_superuser"
]
=
True
other_fields
[
"is_superuser"
]
=
True
other_fields
[
"is_staff"
]
=
True
return
self
.
create_user
(
email
,
**
other_fields
)
return
self
.
create_user
(
email
,
**
other_fields
)
def
get_or_none
(
self
,
*
args
,
**
kw
):
def
get_or_none
(
self
,
*
args
,
**
kw
):
...
...
backend/unittest.py
View file @
33905a7f
...
@@ -103,6 +103,7 @@ class TestBase(nm2.lib.unittest.TestBase):
...
@@ -103,6 +103,7 @@ class TestBase(nm2.lib.unittest.TestBase):
else
:
else
:
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
if
isinstance
(
person
,
str
):
person
=
self
.
persons
[
person
]
person
=
self
.
persons
[
person
]
if
person
is
not
None
:
if
person
is
not
None
:
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
...
@@ -128,6 +129,7 @@ class TestBase(nm2.lib.unittest.TestBase):
...
@@ -128,6 +129,7 @@ class TestBase(nm2.lib.unittest.TestBase):
else
:
else
:
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
raise
NotImplementedError
(
f
"
{
identity
.
issuer
}
not supported as identity during testing"
)
if
isinstance
(
person
,
str
):
person
=
self
.
persons
[
person
]
person
=
self
.
persons
[
person
]
if
person
is
not
None
:
if
person
is
not
None
:
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
client
.
force_login
(
person
,
backend
=
self
.
TEST_AUTH_BACKEND
)
...
...
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
__future__
import
annotations
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.urls
import
reverse
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
):
class
TestPermissions
(
TestBase
,
TestCase
):
@
classmethod
def
test_impersonate_staff
(
self
):
def
__add_extra_tests__
(
cls
):
User
=
get_user_model
()
non_fd
=
[
"pending"
,
"dc"
,
"dc_ga"
,
"dm"
,
"dm_ga"
,
"dd_nu"
,
"dd_u"
,
"dd_e"
,
"dd_r"
,
"activeam"
,
"oldam"
]
visitor
=
User
.
objects
.
create_superuser
(
email
=
"admin@example.org"
,
fullname
=
"Admin"
,
audit_skip
=
True
)
fd
=
[
"fd"
,
"dam"
]
visited
=
User
.
objects
.
create_user
(
email
=
"user@example.org"
,
fullname
=
"User"
,
audit_skip
=
True
)
client
=
self
.
make_test_client
(
visitor
)
for
visitor
in
[
None
]
+
non_fd
:
for
visited
in
non_fd
+
fd
:
cls
.
_add_method
(
cls
.
_test_impersonate_fail
,
visitor
,
visited
)
for
visitor
in
fd
:
response
=
client
.
get
(
reverse
(
"impersonate:whoami"
))
for
visited
in
non_fd
+
fd
:
self
.
assertJSONEqual
(
response
.
content
,
{
cls
.
_add_method
(
cls
.
_test_impersonate_success
,
visitor
,
visited
)
'impersonator'
:
None
,
'impersonator_desc'
:
None
,
'user'
:
visitor
.
pk
,
'user_desc'
:
str
(
visitor
),
})
def
_test_impersonate_success
(
self
,
visitor
,
visited
):
response
=
client
.
post
(
reverse
(
"impersonate:impersonate"
),
data
=
{
"pk"
:
visited
.
pk
,
"next"
:
"/"
})
client
=
self
.
make_test_client
(
visitor
)
response
=
client
.
post
(
reverse
(
"impersonate"
),
data
=
{
"pk"
:
self
.
persons
[
visited
].
pk
,
"next"
:
"/"
})
self
.
assertRedirectMatches
(
response
,
"^/$"
)
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
)
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
)
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"
...
@@ -6,4 +6,5 @@ app_name = "impersonate"
urlpatterns
=
[
urlpatterns
=
[
# Impersonate a user
# Impersonate a user
path
(
'impersonate/'
,
views
.
Impersonate
.
as_view
(),
name
=
"impersonate"
),
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
...
@@ -5,6 +5,7 @@ from django.shortcuts import redirect
from
django.core.exceptions
import
PermissionDenied
from
django.core.exceptions
import
PermissionDenied
from
django.contrib
import
messages
from
django.contrib
import
messages
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth
import
get_user_model
from
django
import
http
class
Impersonate
(
View
):
class
Impersonate
(
View
):
...
@@ -13,7 +14,7 @@ class Impersonate(View):
...
@@ -13,7 +14,7 @@ class Impersonate(View):
effective_user
=
getattr
(
request
,
"impersonator"
,
None
)
effective_user
=
getattr
(
request
,
"impersonator"
,
None
)
if
effective_user
is
None
:
if
effective_user
is
None
:
effective_user
=
request
.
user
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
raise
PermissionDenied
pk
=
request
.
POST
.
get
(
"pk"
)
pk
=
request
.
POST
.
get
(
"pk"
)
if
pk
is
None
:
if
pk
is
None
:
...
@@ -33,3 +34,14 @@ class Impersonate(View):
...
@@ -33,3 +34,14 @@ class Impersonate(View):
return
redirect
(
user
.
get_absolute_url
())
return
redirect
(
user
.
get_absolute_url
())
else
:
else
:
return
redirect
(
url
)
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 = [
...
@@ -88,6 +88,7 @@ MIDDLEWARE = [
'signon.middleware.SignonMiddleware'
,
'signon.middleware.SignonMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'impersonate.middleware.ImpersonateMiddleware'
,
]
]
AUTHENTICATION_BACKENDS
=
[
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