Django Two Factor Authentication Setup - django

I recently asked a question about Django Two Factor authentication here...Django Two Factor Authentication. Based on the feedback I received I am trying to deploy it in my project. I have read the basic installation instructions, but I can't quite figure out how to get it to work in my project...
I have installed it via...
pip install django-two-factor-auth
Then I added it to my settings.py file...
INSTALLED_APPS = (
...
'django_otp',
'django_otp.plugins.otp_static',
'django_otp.plugins.otp_totp',
'two_factor',
)
And I have added it to my settings.py file...
from django.core.urlresolvers import reverse_lazy
LOGIN_URL = reverse_lazy('two_factor:login')
# this one is optional
LOGIN_REDIRECT_URL = reverse_lazy('two_factor:profile')
And I have added it to my urls.py file...
urlpatterns = patterns(
'',
url(r'', include('two_factor.urls', 'two_factor')),
...
)
I was using the LoginView from from django.contrib.auth.views via the following import...
from django.contrib.auth.views import LoginView
I since have changed it to subclass LoginView from two_factor as shown below:
from two_factor.views import LoginView
Then I set up a two_factor/_base.html file in my project directory...
But when I enter the initial credentials of username and password, I get the following message...
SuspiciousOperation at /project/login/
ManagementForm data is missing or has been tampered.
I'm not sure if any more detailed instructions are available...but I've followed what was there and can't seem to figure out how to get this up and going...
For the record, I'm trying to figure out how to incorporate the two factor authentication at the time the user logs in, and then they have to enter a pin number as an example. I'm also trying to force the user at registration time to set this up as a mandatory login method. I realize now that the LoginView that I'm using is incorrect. I need to figure out how to get this properly set up when the user initially registers.
Not sure where to go next with this. Thanks in advance for any thoughts.

After a lot of trial and error...I figured out that I needed to update my settings.py file to account for the fake gateways and I needed to incorporate the logging code to turn on the information messages...
Here is the link to the page that I referenced...
https://django-two-factor-auth.readthedocs.io/en/stable/configuration.html
Once I added the code below to my settings.py file...I was able to get 2FA up and running...
TWO_FACTOR_CALL_GATEWAY = 'two_factor.gateways.fake.Fake'
TWO_FACTOR_SMS_GATEWAY = 'two_factor.gateways.fake.Fake'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'two_factor': {
'handlers': ['console'],
'level': 'INFO',
}
}
}

Related

Unable to configure formatter 'json': Cannot resolve 'app_name.utils.logging.JSONFormatter': cannot import name 'Celery'

I am trying to include celery into our Django app and am struggling with the setup.
So far all my searching of stackoverflow/google tells me I have a circular dependency, but I can't see it. The docs, https://docs.celeryproject.org/en/stable/getting-started/first-steps-with-celery.html, clearly use from celery import Celery
I have defined:
app_name/app_name_celery.py with
from celery import signals, Celery
import os
from django.conf import settings
# disable celery logging so that it inherits from the configured root logger
#signals.setup_logging.connect
def setup_celery_logging(**kwargs):
pass
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
# Create default Celery app
app = Celery('app_name')
# namespace='CELERY' means all celery-related configuration keys
# should be uppercased and have a `CELERY_` prefix in Django settings.
# https://docs.celeryproject.org/en/stable/userguide/configuration.html
app.config_from_object("django.conf:settings", namespace="CELERY")
# When we use the following in Django, it loads all the <appname>.tasks
# files and registers any tasks it finds in them. We can import the
# tasks files some other way if we prefer.
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
Additionally, I have defined app_name/my_app_config.py with
from django.apps import AppConfig
class MyAppConfig(AppConfig):
# ...
def ready(self):
# Import celery app now that Django is mostly ready.
# This initializes Celery and autodiscovers tasks
import app_name.app_name_celery
Lastly, I have added to my __init__.py:
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .app_name import app as celery_app
__all__ = ('celery_app',)
Also, the logging setup is unchanged for this pr, but here it is:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'json': {
'()': 'app_name.utils.logging.JSONFormatter'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'json'
}
},
'loggers': {
'ddtrace': {
'level': 'WARNING'
}
},
'root': {
'level': 'DEBUG',
'handlers': ['console']
}
}
Can anyone see the circular dependency or what else I may be missing?
You are trying to import django settings on
app_name/app_name_celery.py
from celery import signals, Celery
import os
from django.conf import settings # This line here
Also you don't need to import celery into your app config.
Auto discover finds tasks in app/tasks.py, app_2/tasks.py etc.

Django format email django errors

hi i would like create a format for django email errors, the email is automatic send by django in this case get the typical error format:
i would like get in the email report the project name, all type errors(404/500/etc)...
This is my settings:
ADMINS = (
('Diego Avila', 'diego.loachamin#test.com'),
)
#CONFIGURAR PARAMETROS EMAIL
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_SSL = True
EMAIL_HOST = 'mail.test.com'
EMAIL_HOST_USER = 'diego.loachamin#test.com'
EMAIL_HOST_PASSWORD = 'dsdsad'
EMAIL_PORT = 465
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}
please someone suggest or idea.. thanks..!!
Django comes with such features built in. For 500 errors, it's a logging handler called AdminEmailHandler. It will trigger when there's uncaught exceptions, and will include the traceback in the email body.
404 is different. That's not an uncaught exception, but you can intercept those with BrokenLinkEmailsMiddleware and send emails.
To customize how these emails look, you can create your own subclass of either or both of AdminEmailHandler and BrokenLinkEmailsMiddleware. Change the relevant logging and middleware config in settings.py to point to your custom logging handler/middleware.
For the logging handler, you can for example use the format_subject method to add something to the subject line of the outgoing email.
class CustomAdminEmailHandler(AdminEmailHandler):
def format_subject(self, subject):
return '[ project name ]' + super().format_subject(subject)
Both the middleware and the logging handler uses django.core.email.mail-admins() to send the emails.

Django Logger: How to log Username

I am trying to implement logging in my Django project (django 1.11, Python 3.6). I'm using default django logger.
To get the username in log, I have used django-requestlogging 1.0.1.
As of now, I don't have any user other than admin superuser.
When I'm trying a GET request on front-end side, an error occurs that says 'LogSetupMiddleware' is not callable.
What is the reason for this error? How do I make the logging work?
How do I get AnonymousUser in the logs?
File settings.py snippet:
INSTALLED_APPS= [
...
'django_requestlogging',
]
MIDDLEWARE = [
...
'django_requestlogging.middleware.LogSetupMiddleware',
...
]
LOGGING = {
'version': 1,
'formatters': {
'standard' : {
'format': '%(asctime)s %(username)s %(request_method)s',
},
},
}
As I can see here middleware class is really not callable. To fix it you have to override that class like this:
some/middlware/path.py
from django.utils.deprecation import MiddlewareMixin
from django_requestlogging.middleware import LogSetupMiddleware as Original
class LogSetupMiddleware(MiddlewareMixin, Original):
pass
And replace middleware path in settings.py by new one:
some.middleware.path.LogSetupMiddleware

django.request logger not working for get_object_or_404

I have this code for UserDetailsView in Django Rest Framework. I am using django 1.9 and DRF 3.
class UserDetailsView(RetrieveUpdateAPIView):
"""
API endpoint that allows a user to be viewed or edited.
"""
serializer_class = UserDetailsSerializer
permission_classes = (IsAuthenticated,)
def get_object(self):
pk = self.kwargs.get('pk', None)
if not pk or (pk == str(self.request.user.pk)):
return self.request.user
else:
try:
return get_object_or_404(User, id=pk)
except ValueError:
return get_object_or_404(User, username=pk)
I have have my django logger configured as per these settings.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '[%(levelname)s] %(message)s'
},
},
'handlers': {
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/backend_common.log',
'maxBytes': 1024*1024*10,
'backupCount': 10,
'formatter': 'simple',
},
'request_handler': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/backend_requests.log',
'maxBytes': 1024*1024*10,
'backupCount': 10,
'formatter': 'simple',
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
}
},
'loggers': {
'': {
'handlers': ['default'],
'propagate': True,
},
'django.request': {
'handlers': ['request_handler', 'mail_admins'],
'level': 'DEBUG',
'propagate': False,
}
}
}
Now, all django 4xx, 5xx error status code should ideally be logged into backend_requests.log file and they are except 404 status resulting from get_object_or_404. I think 404 errors resulting from this view should also get logged. Any help is highly appreciated.
There are actually two issues here.
The first is a bug in Django, which was fixed just a few days ago. The bit of code that was logging 404s was running a little too early. The next release of Django will work and your 404s will be logged as you would expect.
For other exceptions however, the problem is as follows. Django will log errors if the exceptions that caused them are bubbled up to the core request handler. However if the view or some middleware catches the exception and handles it, then this portion of Django's code never gets called. This is what is happening with DRF:
REST framework's views handle various exceptions, and deal with returning appropriate error responses.
The handled exceptions are:
Subclasses of APIException raised inside REST framework.
Django's Http404 exception.
Django's PermissionDenied exception.
In each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.
Because DRF catches the exception and returns a response object to Django, Django will just render the response and not log the error. This makes sense - it is possible for some middleware to take what was originally a 404 but return a different response instead (the flatpage middleware is a good example).
If you want to log exceptions handled by DRF you can specify your own EXCEPTION_HANDLER in the DRF config, or write your own middleware that logs the errors.
Note that 5xx exceptions are not handled by DRF and these should still propagate up to Django. These should be getting logged for you even now.

Django: logging template errors

When I make an error in a django template {{placeholder}}, I get no error, just blank space in the output where I was expecting content. Is there a way to see something in my logs when this occurs, preferably using logging.warning or logging.error?
Yes, there is. Just add in your development settings.py:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.template': {
'handlers': ['console'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
},
},
}
As roboslone stated, Django 1.9 did introduce it. The snippet is very similar to the second of Configuring logging examples in Django docs.
The only thing Django provides for handling unknown context variables in TEMPLATE_STRING_IF_INVALID. You're going to have to do some deeper hacking of the template engine if you want better than that.
In Django >= 1.8, TEMPLATE_STRING_IF_INVALID has been deprecated in favor of string_if_invalid in settings.TEMPLATES.
If you want to do a little more than depend on DEBUG messages from the django.template logger, you can fool the following code in django.template.base.FilterExpression.render():
if '%s' in string_if_invalid:
return string_if_invalid % self.var
With a class like the following:
class InvalidString(object):
def __mod__(self, other):
log.error('Missing template variable: "%s"', other)
# ... do other interesting things ...
return u''
def __contains__(self, item):
return item == '%s'
And set string_if_invalid in settings.TEMPLATES:
TEMPLATES = [{
'OPTIONS': {'string_if_invalid': InvalidString()}
# ...
}]