Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
David Seaward
Keel - LDH Middleware
Commits
8e71aac4
Commit
8e71aac4
authored
Oct 30, 2017
by
David Seaward
Browse files
authenticate against ldap, fallback on jwt
* if jwt exists, create user in ldap * minor code tidying
parent
49fa8c3f
Changes
2
Hide whitespace changes
Inline
Side-by-side
purist/custom.py
View file @
8e71aac4
import
logging
from
django.conf
import
settings
from
django.contrib.auth.password_validation
import
MinimumLengthValidator
as
BaseValidator
from
django.core
import
validators
from
django.utils.deconstruct
import
deconstructible
from
django.utils.translation
import
ugettext_lazy
as
_
from
django_auth_ldap.backend
import
LDAPBackend
as
BaseBackend
from
woocommerce
import
API
as
WOOCOMMERCE_API
from
.models
import
UserManager
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -14,20 +18,70 @@ class AuthenticationBackend(BaseBackend):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
AuthenticationBackend
,
self
).
__init__
(
*
args
,
**
kwargs
)
def
is_valid_jwt
(
self
,
username
=
None
,
password
=
None
):
is_valid
=
False
try
:
jwt_wcapi
=
WOOCOMMERCE_API
(
url
=
settings
.
WOO_URL
,
# consumer_key=settings.WOO_CONSUMER_KEY,
# consumer_secret=settings.WOO_CONSUMER_SECRET,
wp_api
=
True
,
version
=
"jwt-auth/v1"
,
)
jwt_response
=
jwt_wcapi
.
post
(
"token"
,
{
"username"
:
username
,
"password"
:
password
})
jwt_status
=
jwt_response
.
status_code
jwt_token
=
jwt_response
.
json
().
get
(
"token"
,
None
)
jwt_code
=
jwt_response
.
json
().
get
(
"code"
,
None
)
known_codes
=
[
"[jwt_auth] incorrect_password"
,
"[jwt_auth] invalid_username"
]
if
jwt_status
==
200
and
jwt_token
is
not
None
:
is_valid
=
True
elif
jwt_code
==
403
and
jwt_code
in
known_codes
:
# recognised authentication failure
is_valid
=
False
else
:
# raise exception for an unrecognised failure
raise
Exception
(
"Unrecognised JWT response: %s"
%
(
jwt_response
,))
except
Exception
as
e
:
logging
.
exception
(
"JWT authentication failed with an unrecognised error: %s"
%
(
e
,))
finally
:
return
is_valid
def
authenticate
(
self
,
request
=
None
,
username
=
None
,
password
=
None
,
**
kwargs
):
model
=
self
.
get_user_model
()
username
=
model
.
normalize_username
(
username
)
user_
model
=
self
.
get_user_model
()
normalized_
username
=
user_
model
.
normalize_username
(
username
)
# TODO: also validate, so that existing but invalid usernames are not permitted?
# first attempt LDAP authentication (with early exit)
user
=
super
(
AuthenticationBackend
,
self
).
authenticate
(
request
,
normalized_username
,
password
,
**
kwargs
)
if
user
is
not
None
:
return
user
return
super
(
AuthenticationBackend
,
self
).
authenticate
(
request
,
username
,
password
,
**
kwargs
)
# secondly attempt WooCommerce/JWT authentication
# (if successful, create and return LDAP user, otherwise return None)
if
self
.
is_valid_jwt
(
normalized_username
,
password
):
UserManager
.
create_user
(
username
=
normalized_username
,
email
=
None
,
password
=
password
)
return
super
(
AuthenticationBackend
,
self
).
authenticate
(
request
,
normalized_username
,
password
,
**
kwargs
)
else
:
return
None
# TODO: also validate, so that existing but invalid usernames are not permitted?
@
deconstructible
class
UsernameValidator
(
validators
.
RegexValidator
):
regex
=
r
'^[A-Za-z][A-Za-z0-9]*$'
message
=
_
(
'Enter a valid username. Must start with a letter, followed by letters and numbers. No punctuation or special characters.'
'Enter a valid username. Must start with a letter, followed by letters and numbers.'
' No punctuation or special characters.'
)
...
...
purist/models.py
View file @
8e71aac4
...
...
@@ -21,12 +21,12 @@ class UserManager(BaseUserManager):
def
create_user
(
self
,
username
,
email
=
None
,
password
=
None
,
**
extra_fields
):
"""Create regular users in LDAP, with no Django password."""
user
=
super
(
UserManager
,
self
).
create_user
(
username
,
email
,
password
,
**
extra_fields
)
return
super
(
UserManager
,
self
).
create_user
(
username
,
email
,
password
,
**
extra_fields
)
def
create_superuser
(
self
,
username
,
email
=
None
,
password
=
None
,
**
extra_fields
):
"""Create superusers with a Django password."""
super
(
UserManager
,
self
).
create_superuser
(
username
,
email
,
password
,
**
extra_fields
)
return
super
(
UserManager
,
self
).
create_superuser
(
username
,
email
,
password
,
**
extra_fields
)
class
User
(
AbstractUser
):
...
...
@@ -53,10 +53,11 @@ class User(AbstractUser):
username
=
super
(
User
,
cls
).
normalize_username
(
username
)
username
=
username
.
lower
()
suffix
=
"@"
+
settings
.
SITE_DOMAIN
.
lower
()
offset
=
0
-
len
(
suffix
)
suffix
=
"@"
+
settings
.
SITE_DOMAIN
if
username
.
endswith
(
suffix
):
username
=
username
[:
-
len
(
suffix
)
]
username
=
username
[:
offset
]
return
username
...
...
@@ -81,7 +82,7 @@ class User(AbstractUser):
def
get_identity
(
self
):
# TODO: associated with https://code.puri.sm/purist/account_web/issues/25
return
self
.
get_username
()
+
"@"
+
settings
.
SITE_DOMAIN
return
self
.
get_username
()
+
"@"
+
settings
.
SITE_DOMAIN
.
lower
()
def
save
(
self
,
force_insert
=
False
,
force_update
=
False
,
using
=
None
,
update_fields
=
None
):
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a 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