Adding a Dynamic Email Backend in Django - python

I would like to let my users decide their email backend on their own. That is why I have created the email relevant keys (host, port, username...) on the users and now I try to work this (see below) backend into my Django project. Working with the docs and the source code, my first attempt was to extend the default EmailBackend by my custom "UserBackend" which overrides the __init__ function like this:
class UserBackend(EmailBackend):
def __init__(self, user_id, host=None, port=None, username=None ...):
user = User.objects.get(id=user_id)
super().init(host=user.email_host, port=user.email_port ...)
As this method is called (I tried to send_mail from the shell) it gets no user_id. How can I approach this differently or how would I extend my attempts to do this? I wouldn't want to rewrite Djangos mail system entirely, as it works in itself.

send_email has a parameter called connection (link to docs) which seems to fit perfectly. You can get a connection by calling get_connection (link to docs) with the user's parameters.
connection = get_connection(host=user.email_host, port=user.email_port, ...)
send_email(connection=connection, ...)
If you'd like to support multiple backend types, get_connection also supports it.

Related

Getting user`s UUID from django server

I have a django server with an admin panel.
Different users make changes there and this is saved via auditlog in the database and displayed in the "history".
But there are situations when a user enters under the account of another user and makes changes on his behalf.
In order to identify from which device this or that change was made, it was a nice decision to also record data about the IP of the user from whom the change was made, and his unique device number.
By overloading several methods in the "AuditlogMiddleware" class, I got the desired result via "uuid.UUID(int=uuid.getnode())".
(Tested locally, because the prod server is heavily loaded and there is no way to do test committees)
from __future__ import unicode_literals
import threading
import time
from auditlog.middleware import AuditlogMiddleware
threadlocal = threading.local()
class ExtendedAuditlogMiddleware(AuditlogMiddleware):
def process_request(self, request):
threadlocal.auditlog = {
'signal_duid': (self.__class__, time.time()),
'remote_addr': request.META.get('REMOTE_ADDR'),
}
super(ExtendedAuditlogMiddleware, self).process_request(request)
**#changes here
import uuid
threadlocal.auditlog['additional_data'] = str(uuid.UUID(int=uuid.getnode()))+" | "+request.META["USERNAME"]**
# #staticmethod
def set_actor(self, user, sender, instance, signal_duid, **kwargs):
super(ExtendedAuditlogMiddleware, self).set_actor(user, sender, instance, signal_duid, **kwargs)
**#changes here
instance.additional_data = threadlocal.auditlog['additional_data']**
But the problem is that I think I get the UUID not of the user, but of the server, because there is no access to the user, i guess. I couldn't find the information, and I couldn't come up with my own solution either.
Question - is it even possible to get information from the server about django admin users' devices??
If not, what can i use instead of UUID to identify which device was used while making changes in django admin panel??
Thank you all in advance!
try to use javascript in side of your template to send this info thrugh

Django how to use connection_created signal

I am looking to find out when a connection is made to my Django database, or when my Django server is restarted. I found the connection_created Django signal. The description is:
Sent when the database wrapper makes the initial connection to the database. This is particularly useful if you’d like to send any post connection commands to the SQL backend.
So I think using this signal will be a good solution for my case. I want to run a function once the connection is made. I can't find any documentations on the use cases of this signal. connection_created.connect is probably the function to use. This function takes in a bunch of arguments, but the ones that are relevant are self, receiver, sender and weak. Does anyone know how I can use these arguments and this function to run my function at a new connection instance?
Also if anyone has any alternative solutions other than this signal, I'd love to hear them.
I have all my tables distributed among dynamic postgres table schemas, and use the connection signal to set the search path of the connection, since django does not support postgres schemas.
in myapp/apps.py
from django.db.backends.signals import connection_created
class MyappConfig(AppConfig):
name = 'myapp'
def ready(self):
from myapp.schema_manager import new_connection
connection_created.connect(new_connection)
in myapp/schema_manager.py
def new_connection(sender, connection, **kwargs):
search_path = ['public'] + get_current_schemas() # fetch the active schemas
connection.cursor().execute("SET search_path TO %s;" % ', '.join(search_path)
According to the docs, this signal receives two arguments:
sender
The database wrapper class – i.e. django.db.backends.postgresql.DatabaseWrapper or django.db.backends.mysql.DatabaseWrapper, etc.
connection
The database connection that was opened. This can be used in a multiple-database configuration to differentiate connection signals from different databases.
... since django does not support postgres schemas
Django supports postgres schemas:
class MyModel(models.Model):
id = models.IntegerField(primary_key=True)
title = models.TextField()
class Meta:
db_table = '"schema_name"."table_name"'
I use this notation in all of our projects.

Custom authentication method for Flask-Security

I'm using flask security to authenticate users. I've made sure the authentication works properly with the http_auth_required decorator - the user is being validated against the userstore (an SQLAlchemyUserDatastore in my case), and all is well.
I would like now to use my own authentication method (I'll be using a custom LDAP validation system), while still taking advantage of the things Flask-Security is giving me (things like current_user). I wrote a custom decorator that looks like this:
def authenticate_with_ldap(func):
#wraps(func)
def wrapper(*args, **kwargs):
if not request.authorization:
return unauthorized_user_handler()
user = user_datastore.get_user(request.authorization.username)
if not user or not authenticate_with_ldap(user.email, user.password):
return unauthorized_user_handler()
return func(*args, **kwargs)
return wrapper
However, when I look at the http_auth_required decorator I see that it uses a private function called _check_http_auth that is doing some stuff that I can't do on my own without accessing private members, like setting the user to the top of the request context stack and sending signals. The code looks like this:
def _check_http_auth():
auth = request.authorization or BasicAuth(username=None, password=None)
user = _security.datastore.find_user(email=auth.username)
if user and utils.verify_and_update_password(auth.password, user):
_security.datastore.commit()
app = current_app._get_current_object()
_request_ctx_stack.top.user = user
identity_changed.send(app, identity=Identity(user.id))
return True
return False
So my question is: what is the correct way to have a custom authentication method, while still utilizing Flask-Security to its fullest?
You can accomplish this with a quick monkey patch. Not ideal, but I'm not sure what else you can do until the Flask-Security team writes in a more elegant way to handle this.
import flask_security
def verify_and_update_password_custom(password, user):
return user.verify_password(password)
flask_security.forms.verify_and_update_password = verify_and_update_password_custom
I'm not sure if it is used anywhere else. The above works for my own purposes. If it does get called elsewhere, you would just need to monkeypatch it into place wherever that is.

Username available in all templates

I'm trying to make the currently logged in username available in all templates. I can receive it from pyramid.security.authenticated_userid, but to do that I need the request object. I tried to go via the BeforeRender subscription, but as far as I can tell, the request in not passed to that callback.
How else can I make the username available everywhere (or in the base template really)?
A common method is to attach the user object to the request via this cookbook recipe.
Another possibility is to attach it as you suggested using a BeforeRender subscriber. The request is available from the event:
def add_renderer_globals(event):
request, context = event['request'], event['context']
event['user'] = authenticated_userid(request)

How do I use repoze.who/repoze.what with SPNEGO?

I'm trying to do single sign-on (SSO) with an intranet web application written in Pylons and I'd like to use repoze.what for authorization. I have Apache configured with mod_sspi and it correctly authenticates the user and sets the REMOTE_USER environment variable. However, I can't figure out how to convince repoze.who that the user is, indeed, authenticated.
I tried creating an Identifier that looks like this:
class NtlmIdentifier(object):
def identify(self, environ):
if environ['AUTH_TYPE'] == 'NTLM':
return { 'repoze.who.userid': environ['REMOTE_USER'] }
return None
def remember(self, environ, identity):
pass
def forget(self, environ, identity):
pass
And registering the middleware later on like this:
return setup_auth(app, groups, permissions, identifiers=identifiers, authenticators=[], challengers=[])
But it seems that my identifier's identify method is never called by the framework.
How do you integrate SPNEGO/SSPI with repoze.who and repoze.what?
When the REMOTE_USER variable is set beforehand (e.g., by the web server), repoze.who won't do anything, not even call the registered plugins.
As for repoze.what v1, because it is set up from a repoze.who plugin, this means the repoze.what credentials won't be available and therefore the user would always be anonymous; this won't be a problem in repoze.what 2 (under development).
To make everything work as you expect, you can keep the identifier you wrote and pass the remote_user_key argument to setup_auth:
return setup_auth(app, groups, permissions, remote_user_key=None, identifiers=identifiers, authenticators=[], challengers=[])
HTH.

Categories

Resources