Getting Logged in User Info in Flask using LDAP - python

I am trying to find a way to retrieve information such as 'mail', 'displayName', 'telephoneNumber' from an LDAP authenticated/logged in user in Flask.
My user can successfully authenticate and log in using LDAP. However how would I be able to get additional information about the user?
I am using standard python-ldap and flask-login modules and I'm trying to create a string variable for these attributes so I can call on them later in the session. When trying to run the query I am getting ldap.FILTER_ERROR: {'desc': u'Bad search filter'} . Any ideas on how to get this working?
class UserInfo():
def whoami(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(username,password)
basedn = 'OU=...,OU=...,DC=...,DC=...'
userfilter = "(|(SamAccountName=\*" + username + "\*)"
userattribute = ['displayName']
userresults = conn.search_s(basedn,ldap.SCOPE_SUBTREE,userfilter, userattribute)
userinfos = UserInfo()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100))
def __init__(self, username, password):
self.username = username
#staticmethod
def try_login(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(domain+username, password)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.before_request
def get_current_user():
g.user = current_user

I needed to use ldap.filter.filter_format for proper character escaping.
import ldap.filter
criteria= ldap.filter.filter_format('(&(objectClass=user)(sAMAccountName=%s))', [username])

Related

Python Flask LDAP connect user with sAMAccountname

I am developing a web app and trying to connect our company users through our AD using there sAMAccountname as they are used to. So far, I can connect users with their DistinguishedName but I can't find the way to do it with the sAMAccountname, any clue ?
in my init.py I have :
app.config['SQLALCHEMY_DATABASE_URI'] = 'connection_to_db'
app.config['SECRET_KEY'] = 'secret_key'
# The Attribute you want users to authenticate to LDAP with.
app.config['LDAP_USER_LOGIN_ATTR'] = 'sAMAccountName'
app.config['LDAP_PROVIDER_URL'] = 'connection_to_ldap'
app.config['LDAP_PROTOCOL_VERSION'] = 3
db = SQLAlchemy(app)
and in my models.py I have :
def get_ldap_connection():
conn = ldap.initialize(app.config['LDAP_PROVIDER_URL'])
return conn
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(100))
def __init__(self, username, password):
self.username = username
#staticmethod
def try_login(username, password):
conn = get_ldap_connection()
res = conn.simple_bind_s(
'CN=%s,DC=example,DC=com' % username,
password
)
# conn.unbind()
print(res)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return str(self.id)
Thanks in advance

Make peewee model JSON serializable?

I have been working on a small web app and I decided it would be a good idea if I used email verification. Well, when I attempted to add email verification I sort of broke my code... I keep getting a traceback telling me the following:
TypeError: <'peewee.CharField object at 0x7f46c6a7ba50> is not JSON serializable
I have come to the conclusion that I need to make my users model JSON serializable but I am not 100% sure that's what I need to do. Even if I am right, I wouldn't know how to do that.
Here is my user model:
class User(UserMixin, Model):
username = CharField(unique=True)
password = CharField(max_length=20)
email = CharField(unique=True)
confirmed = BooleanField(default=False)
confirmed_on = DateTimeField(default=datetime.datetime.now())
joined_at = DateTimeField(default=datetime.datetime.now)
class Meta:
database = db
order_by = ('-joined_at',)
#classmethod
def create_user(cls, username, email, password, confirmed):
try:
with db.transaction():
cls.create(
username=username,
email=email,
password=generate_password_hash(password),
confirmed=False)
except IntegrityError:
raise ValueError("User already exists")
as far as email verification goes here is what I tried:
def generate_serializer(secret_key=None):
return URLSafeTimedSerializer(app.config['SECRET_KEY'])
def generate_activation_url(user):
serializer = generate_serializer()
token = serializer.dumps(user.username)
return url_for('activate_user', token=token, _external=True)
#app.route('/', methods=('GET', 'POST'))
def index():
form = forms.RegisterForm()
if form.validate_on_submit():
models.User.create_user(
username=form.username.data,
email=form.email.data,
password=form.password.data,
confirmed=False
)
token = generate_activation_url(models.User)
msg =Message(render_template('activation_email.html', token=token),
recipients=[models.User.email])
mail.send(msg)
return render_template('activate.html', user=models.User)
return render_template('index.html', form=form)
#app.route('/activate/<token>')
def activate_user(token, expiration=3600):
serializer = generate_serializer()
try:
serializer.loads(token, salt=app.config[
'SECRET_KEY'], max_age=expiration)
except (BadSignature, SignatureExpired):
abort(404)
models.User.confirmed = True
flash('User activated')
return redirect(url_for('index'))

AttributeError: 'SelectQuery' object has no attribute 'is_active'

I'm trying to learn the Peewee ORM in combination with Flask by following the Flask Mega Tutorial. In part 5 of the tutorial I create a login using OpenID. After overcoming a bunch of hurdles already I now get an AttributeError in the function pasted below on the following line: login_user(user, remember = remember_me).
#oid.after_login
def after_login(resp):
if resp.email is None or resp.email == "":
flash('Invalid login. Please try again.')
return redirect(url_for('login'))
user = User.select().where(User.email == resp.email)
if user.wrapped_count() == 0:
nickname = resp.nickname
if nickname is None or nickname == "":
nickname = resp.email.split('#')[0]
user = User(nickname = nickname, email = resp.email, role = models.ROLE_USER)
user.save()
remember_me = False
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user, remember = remember_me)
return redirect(request.args.get('next') or url_for('index'))
is_active is found in my User model as follows:
class User(db.Model):
nickname = TextField()
email = TextField()
role = IntegerField(default = ROLE_USER)
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return self.id
def __repr__(self):
return '<User %r>' % (self.nickname)
I have no clue what I'm doing wrong here though. Could anybody give me a helping hand in what I'm doing wrong here?
All tips are welcome!
As the error suggests, user = User.select().where(User.email == resp.email) gives you back a SelectQuery, not an instance of User. You'll want to include an additional method call to actually fetch the record, something like .first(). first will return either an instance of User or None.
This would allow you to slightly adjust your code:
user = User.select().where(User.email == resp.email).first()
if not user: # or if user is None:
nickname = resp.nickname
...

proper use of auth.login_required in 'flask peewee'

I have a custom admin class. HOw auth.login_required be used...Simply using #auth.login_required as a decorator is not helping. My code snippet
my_model.py
class User(db.Model, BaseUser):
username = CharField()
password = CharField()
email = CharField(default='')
active = BooleanField(default=False)
#...other fields
def is_active(self):
return self.active
def is_anonymous(self):
return False
def is_authenticated(self):
return True
def __unicode__(self):
return self.username
auth.py
class CustomAuth(Auth):
def get_user_model(self):
return User
def get_model_admin(self):
return UserAdmin
# instantiate custom auth
auth = CustomAuth(app, db, user_model=User)
usuage
#some_url.route('/some_url')
#auth.login_required # ITS NOT WORKIN
def some_url():
return "test url"
Try this
#some_url.route('/some_url')
#auth.login_required # ITS NOT WORKIN
def some_url():
user = auth.get_logged_in_user()
return "test url"

flask-login not sure how to make it work using sqlite3

So far I made my user object and my login function, but I don't understand the user_loader part at all. I am very confused, but here is my code, please point me in the right direction.
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
user=request.form['name']
passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [passw])
passwcorrect = c.fetchone()
if passwcorrect:
#session['logged_in']=True
#login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
my user
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated():
return True
#return true if user is authenticated, provided credentials
def is_active():
return True
#return true if user is activte and authenticated
def is_annonymous():
return False
#return true if annon, actual user return false
def get_id():
return unicode(self.id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
my database
import sqlite3
import sys
import datetime
conn = sqlite3.connect('data.db')#create db
with conn:
cur = conn.cursor()
cur.execute('PRAGMA foreign_keys = ON')
cur.execute("DROP TABLE IF EXISTS posts")
cur.execute("DROP TABLE IF EXISTS users")
cur.execute("CREATE TABLE users(id integer PRIMARY KEY, username TEXT, password TEXT, email TEXT)")
cur.execute("CREATE TABLE posts(id integer PRIMARY KEY, body TEXT, user_id int, FOREIGN KEY(user_id) REFERENCES users(id))")
I also set up the LoginManager in my init. I am not sure what to do next, but I know I have to some how set up this
#login_manager.user_loader
def load_user(id):
return User.query.get(id)
how do I adjust this portion code to work for my database?
EDIT: please let me know if this looks correct or can be improved :)
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT id from users where username = (?)", [id])
userid = c.fetchone()
return userid
#app.route('/login', methods=['GET','POST'])
def login():
form = Login()
if form.validate():
g.user=request.form['name']
g.passw=request.form['password']
c = g.db.execute("SELECT username from users where username = (?)", [g.user])
userexists = c.fetchone()
if userexists:
c = g.db.execute("SELECT password from users where password = (?)", [g.passw])
passwcorrect = c.fetchone()
if passwcorrect:
user = User(g.user, 'email', g.passw)
login_user(user)
flash("logged in")
return redirect(url_for('home'))
else:
return 'incorrecg pw'
else:
return 'fail'
return render_template('login.html', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
import sqlite3
from flask import g
class User():
def __init__(self,name,email,password, active = True):
self.name = name
self.email = email
self.password = password
self.active = active
def is_authenticated(self):
return True
#return true if user is authenticated, provided credentials
def is_active(self):
return True
#return true if user is activte and authenticated
def is_annonymous(self):
return False
#return true if annon, actual user return false
def get_id(self):
c = g.db.execute('SELECT id from users where username = (?)', [g.user])
id = c.fetchone()
return unicode(id)
#return unicode id for user, and used to load user from user_loader callback
def __repr__(self):
return '<User %r>' % (self.email)
def add(self):
c = g.db.execute('INSERT INTO users(username,email,password)VALUES(?,?,?)',[self.name,self.email,self.password])
g.db.commit()
user_loader callback function is a way to tell Flask-Login on "how" to look for the user id from the database ? Since you are using sqllite3, you need to implement the user_loader function to query your sqllite database and fetch/return the userid/username that you have stored. Something like:
#login_manager.user_loader
def load_user(id):
c = g.db.execute("SELECT username from users where username = (?)", [id])
userrow = c.fetchone()
userid = userrow[0] # or whatever the index position is
return userid
When you call login_user(user), it calls the load_user function to figure out the user id.
This is how the process flow works:
You verify that user has entered correct username and password by checking against database.
If username/password matches, then you need to retrieve the user "object" from the user id. your user object could be userobj = User(userid,email..etc.). Just instantiate it.
Login the user by calling login_user(userobj).
Redirect wherever, flash etc.
Are you using SQLAlchemy by any chance?
Here is an example of my model.py for a project I had a while back that used Sqlite3 & Flask log-ins.
USER_COLS = ["id", "email", "password", "age"]
Did you create an engine?
engine = create_engine("sqlite:///ratings.db", echo=True)
session = scoped_session(sessionmaker(bind=engine, autocommit=False, autoflush=False))
Base = declarative_base()
Base.query = session.query_property()
Base.metadata.create_all(engine)
Here is an example of User Class:
class User(Base):
__tablename__ = "Users"
id = Column(Integer, primary_key = True)
email = Column(String(64), nullable=True)
password = Column(String(64), nullable=True)
age = Column(Integer, nullable=True)
def __init__(self, email = None, password = None, age=None):
self.email = email
self.password = password
self.age = age
Hope that helps give you a little bit of a clue.
Use SQLAlchemy it completely handles all the queries for you, so you don't have to write it all out.
But if you continue using it this way, then your user_loader function should create a "User" class object. Like:
userrow = c.fetchone()
username = userrow[0]
u = User(username=username)
return u

Categories

Resources