Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update and fix authenticator device #20

Merged
merged 1 commit into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ Flexible authentication for web, mobile, desktop and hybrid apps. It can be used
Full list of supported services and corresponding identifiers:
- Email
- Phone (as Sms)
- GoogleAuthentication (soon)
- Yubikey (soon)
- WhatsApp
- Google Authenticator
- Microsoft Authenticator
- Authy, andOTP, etc
- Yubikey (soon)
- ...add yours

and service providers:
Expand Down Expand Up @@ -90,7 +92,7 @@ Custom use cases and how to config or code them.

#### APIs

Package contains full set of [rest api endpoints](./multauth/api/urls.py), but it's optional. To use it, `djangorestframework>=3.10.3` should be installed and the urls be included:
Package contains full set of [rest api endpoints](./multauth/api/urls.py), but it's optional. To activate it, `djangorestframework>=3.10.3` should be installed and the urls be included:
```
urlpatterns = [
path(r'^', include('multauth.api.urls')),
Expand Down
2 changes: 1 addition & 1 deletion multauth/api/devices/authenticator/me/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@


class UserAuthenticatorKeySerializer(serializers.Serializer):
pass
key = serializers.CharField()
53 changes: 24 additions & 29 deletions multauth/api/devices/authenticator/me/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,31 @@ def get(self, request):
user = request.user

try:
user = request.user
device = user.get_authenticator_device()
key = device.key_b32
key = device.key_b32.decode()
result = serializers.UserAuthenticatorKeySerializer({
'key': key,
})

return Response(result.data, status=status.HTTP_200_OK)

except AuthenticatorDevice.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

# @swagger_auto_schema(
# operation_description='Set push notification code, aka token',
# operation_description='Set and get authenticator key',
# request_body=serializers.UserAuthenticatorPushcodeSerializer,
# )
# def post(self, request):
# serializer = serializers.UserAuthenticatorPushcodeSerializer(data=request.data)
# serializer.is_valid(raise_exception=True)

# try:
# user = request.user
# device = user.get_phone_device()
# device.pushcode = serializer.validated_data['pushcode'];
# device.save()
def post(self, request):
user = request.user

# return Response(status=status.HTTP_200_OK)
try:
device = user.get_authenticator_device()
device.set_key()
return self.get(request)

# except AuthenticatorDevice.DoesNotExist:
# return Response(status=status.HTTP_404_NOT_FOUND)
except AuthenticatorDevice.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)


class MeAuthenticatorKeyImageView(views.APIView):
Expand All @@ -68,7 +68,6 @@ def get(self, request):
user = request.user

try:
user = request.user
device = user.get_authenticator_device()
uri = device.key_uri

Expand All @@ -81,20 +80,16 @@ def get(self, request):
return Response(status=status.HTTP_404_NOT_FOUND)

# @swagger_auto_schema(
# operation_description='Set push notification code, aka token',
# operation_description='Set and get authenticator key',
# request_body=serializers.UserAuthenticatorPushcodeSerializer,
# )
# def post(self, request):
# serializer = serializers.UserAuthenticatorPushcodeSerializer(data=request.data)
# serializer.is_valid(raise_exception=True)

# try:
# user = request.user
# device = user.get_phone_device()
# device.pushcode = serializer.validated_data['pushcode'];
# device.save()
def post(self, request):
user = request.user

# return Response(status=status.HTTP_200_OK)
try:
device = user.get_authenticator_device()
device.set_key()
return self.get(request)

# except AuthenticatorDevice.DoesNotExist:
# return Response(status=status.HTTP_404_NOT_FOUND)
except AuthenticatorDevice.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
17 changes: 10 additions & 7 deletions multauth/devices/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@


# see django_otp.plugins.otp_totp.models.TOTPDevice
def default_key():
def key_generator():
return random_hex(MULTAUTH_KEY_LENGTH)


Expand All @@ -46,7 +46,7 @@ def key_validator(value):

class AuthenticatorDevice(ThrottlingMixin, AbstractDevice):
# see django_otp.plugins.otp_totp.models.TOTPDevice
key = models.CharField(max_length=80, validators=[key_validator], default=default_key) # a hex-encoded secret key of up to 40 bytes
key = models.CharField(max_length=80, validators=[key_validator], default=key_generator) # a hex-encoded secret key of up to 40 bytes
step = models.PositiveSmallIntegerField(default=30) # the time step in seconds.
t0 = models.BigIntegerField(default=0) # the Unix time at which to begin counting steps
digits = models.PositiveSmallIntegerField(choices=[(6, 6), (8, 8)], default=6) # the number of digits to expect in a token
Expand Down Expand Up @@ -105,6 +105,11 @@ def save(self, *args, **kwargs):
self.key = self.generate_key()
return super().save(*args, **kwargs)

def set_key(self, raw_hardcode):
self.key = key_generator()
self.save(update_fields=['key'])
return self.key

def generate_totp(self, request=None):
key = self.bin_key
totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
Expand All @@ -115,9 +120,7 @@ def generate_challenge(self, request=None):
totp = self.generate_totp()

if MULTAUTH_DEBUG:
print('Fake auth message, Google Authenticator, token: %s ' % (totp))

return totp
print('Fake auth message, Google Authenticator, token: %s ' % (totp.token()))

# see django_otp.plugins.otp_totp.models.TOTPDevice
def verify_token(self, token):
Expand All @@ -130,12 +133,12 @@ def verify_token(self, token):
except Exception:
verified = False
else:
totp = generate_totp()
totp = self.generate_totp()
verified = totp.verify(token, self.tolerance, self.last_t + 1)

if verified:
self.last_t = totp.t()
if MULTAUTH_THROTTLE_SYNC:
if MULTAUTH_SYNC:
self.drift = totp.drift
self.throttle_reset(commit=False)
self.save()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def read(f):

setup(
name='django-multifactor-authentication',
keywords='django authentication multifactor mfa 2fa 3fa user signin signup twillio sendgrid nexmo sns',
keywords='django authentication multifactor mfa 2fa 3fa user signin signup otp google microsoft authenticator authy andotp whatsapp telegram yubikey twillio sendgrid nexmo sns',
version='1.1.0',
url='https://github.com/andrenerd/django-multifactor-authentication',
license='BSD',
Expand Down