I'm new to Flask, I'm using the apache-superset in version 0.38.0.
In it I'm using an LDAP authentication method, everything is functional.
However, I have another system in the company, which also uses LDAP to login, proprietary system. The idea is that when the user is logged in to our system and is going to enter the superset, he is already logged in, taking advantage of the credentials used in our system, since both are use LDAP.
What I've found so far: Apparently this is the class that authenticates LDAP credentials:
class AuthLDAPView(AuthView):
login_template = "appbuilder/general/security/login_ldap.html"
#expose("/login/", methods=["GET", "POST"])
def login(self):
if g.user is not None and g.user.is_authenticated:
return redirect(self.appbuilder.get_url_for_index)
form = LoginForm_db()
if form.validate_on_submit():
user = self.appbuilder.sm.auth_user_ldap(
form.username.data, form.password.data
)
if not user:
flash(as_unicode("Usuário não Encontrado ou Instabilidade no servidor LDAP"), "warning")
return redirect(self.appbuilder.get_url_for_login)
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return self.render_template(
self.login_template, title=self.title, form=form, appbuilder=self.appbuilder
)
the credentials apparently received through LoginForm_db ():
class LoginForm_db(DynamicForm):
username = StringField(lazy_gettext("User Name"), validators=[DataRequired()])
password = PasswordField(lazy_gettext("Password"), validators=[DataRequired()])
which in turn receives the values from the login screen that is written in flask in the following:
<form class="form" action="" method="post" name="login">
{{form.hidden_tag()}}
<div class="help-block">{{_("Enter your login and password below")}}:</div>
<div class="control-group{% if form.errors.openid is defined %} error{% endif %}">
<label class="control-label" for="openid">{{_("Username")}}:</label>
<div class="controls">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
{{ form.username(size = 80, class = "form-control", autofocus = true) }}
</div>
{% for error in form.errors.get('openid', []) %}
<span class="help-inline">[{{error}}]</span><br>
{% endfor %}
<label class="control-label" for="openid">{{_("Password")}}:</label>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-key"></i></span>
{{ form.password(size = 80, class = "form-control") }}
</div>
{% for error in form.errors.get('openid', []) %}
<span class="help-inline">[{{error}}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group">
<div class="controls">
<br>
<input class="btn btn-primary btn-block" type="submit" value="{{_('Logar')}}">
</div>
</div>
</form>
I was thinking of doing something that can send the credentials authenticated in our proprietary system (developed in java) through the url and receive them in this form of the superset and consequently log in.
I'm almost sure it shouldn't be the safest method, but I'm a beginner in programming and can't think of anything better. Maybe the Token but I don't even know where to start.
User logged into another system, (where I can redeem the user and password), when redirected to the superset, must be automatically logged in. How to do this ?
You can create a RESTful API to handle user authentication as below
from flask import request, make_response, jsonify, session
from flask_appbuilder.api import BaseApi, expose, rison, safe
from flask_appbuilder.security.decorators import protect
from . import appbuilder
from flask_login import current_user, login_user
from app import db
class LoginApi(BaseApi):
resource_name = "login"
#expose('/loginapi/', methods=['GET','POST'])
##has_access
def loginapi(self):
if request.method == 'POST':
username = request.json['username']
password = request.json['password']
user = self.appbuilder.sm.auth_user_db(username, password)
if str(user) != "None":
login_user(user, remember=False)
if current_user.is_active:
username = current_user.username
status = current_user.active
response = make_response(jsonify({'message': 'Login Success',
'severity': 'info','Username':
username,'Status':status}))
return response
For details on how to create a REST API refer to this this.
https://flask-appbuilder.readthedocs.io/en/latest/rest_api.html
Related
I have done a registration and login page registration page works fine but login page when i Click on create account i get object has no attribute.
application.py
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import Length,EqualTo,InputRequired,ValidationError
from models import User
#app.route('/login', methods=['GET', 'POST'])
def login():
login_form = LoginForm()
if login_form.validate_on_sumbit():
return "Logged in, finally!"
return render_template('login.html', form=login_form)
#wtform_fields.py
class LoginForm(FlaskForm):
"""Login Form """
username = StringField('username_label',validators=[InputRequired(message="username required")])
password = PasswordField('password_label',validators=[InputRequired(message="Password required"),invalid_credentials])
submit = SubmitField('Login')
login.html
{% from 'form_helper.html' import DisplayField %}
{% extends "prelogin-layout.html" %}
{% block title %} Registration {% endblock %}
{% block content %}
<h3>Create your account</h3>
<hr>
<form action="{{ url_for('index') }}", method="POST" >
{{DisplayField(form.username, 'Username', autocomplete='off',autofocus=true)}}
{{DisplayField(form.password, 'Password')}}
{{DisplayField(form.confirm, 'Confirm Password')}}
<div class="form-group">
<input type="submit" value="Create" >
</div>
{{form.csrf_token}}
</form>
{% endblock %}
ErrorLog
in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\Catalyst\Desktop\Python\chatAp\application.py", line 18, in login
if login_form.validate_on_sumbit():
AttributeError: 'LoginForm' object has no attribute 'validate_on_sumbit'
I'm new at flask can you direct e where I'm mistaken
PS I'm working with flaskwtf V1.0.1
Change the line that adds submit in login.html from
<div class="form-group">
<input type="submit" value="Create" >
</div>
to
<div class="form-group">
{{DisplayField(form.submit, 'Create')}}
</div>
If you are using Flask WTF all fields in the form must come from the library.
P.S.
I don't know where you got the confirm variable to check the password from.
It may not work for you either. If you want the user to enter the password twice, read here: wtforms.validators.EqualTo
I am trying to build a simple web app, which has a form to change one's password. I am using werkzeug.security functions (check_password_hash and generate_password_hash) to do so. This two functions work perfectly in during registering and logging in. But for some reason, when I change password, the password just doesn't match. I even wrote a code to check the password right away, passwordChange = check_password_hash(newHash, newPassword), then print(f'\n\n{passwordChange}\n\n')but for some reason it always returned false. Here is the full code. Any response is greatly appreciated :)
FLASK
#app.route("/passwordchange", methods=["GET", "POST"])
#login_required
def changepassword():
""""Change users' password"""
if request.method == "POST":
newPassword = request.form.get("newPassword")
newConfirmation = request.form.get("newConfirmation")
# Ensure that the user has inputted
if (not newPassword) or (not newConfirmation):
return apology("Please fill all of the provided fields!", 400)
# Check to see if password confirmation were the same or not
if newPassword != newConfirmation:
return apology("password did not match with password (again)", 400)
user_id = session["user_id"]
newHash = generate_password_hash("newPassword")
db.execute("UPDATE users SET hash = ? WHERE id = ?", newHash, user_id)
passwordChange = check_password_hash(newHash, newPassword)
print(f'\n\n{passwordChange}\n\n')
return redirect("/login")
else:
return render_template("password.html")
HTML
{% extends "layout.html" %}
{% block title %}
Change Password
{% endblock %}
{% block main %}
<form action="/passwordchange" method="post">
<div class="form-group">
<input class="form-control" name="newPassword" placeholder="New Password" type="password">
</div>
<div class="form-group">
<input class="form-control" name="newConfirmation" placeholder="New Password (again)" type="password">
</div>
<button class="btn btn-primary" type="submit">Change Password</button>
</form>
{% endblock %}
I'm trying to setup a flask webapp with some basic login/register system controlled by flask-WTF forms.
Here is my code:
html
<!-- Register form -->
<div class="form">
<div class="form-area">
<h2>Register</h2>
<form action="{{ url_for('register') }}">
{{ form.csrf_token() }}
{{ form.hidden_tag() }}
{{ form.name(placeholder='name') }}
{{ form.surname(placeholder='surname') }}
{{ form.email(placeholder='email') }}
{{ form.password(placeholder='password') }}
{{ form.confirm_password(placeholder='confirm password') }}
<input type="submit" value="Register">
</form>
<p>Already registered? Log in here</p>
</div>
<div class="error-area">
{% for error in form.confirm_password.errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
</div>
class
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import InputRequired, Length, EqualTo
class RegisterForm(FlaskForm):
name = StringField('name', validators=[InputRequired()])
surname = StringField('surname', validators=[InputRequired()])
email = StringField('email', validators=[InputRequired()])
password = PasswordField('password', validators=[InputRequired(), Length(min=6)])
confirm_password = PasswordField('confirm passord', validators=[InputRequired(), Length(min=6), EqualTo(password)])
flask
#app.route('/register')
def register():
#declare a register form
form = RegisterForm()
#validate form
if form.validate_on_submit():
print('validate')
return '<h1>Success</h1>'
else:
print('not validated')
print(form.errors)
return render_template('register.html', form=form)
The problem with my code is that validation seems not to be working. Even if I fill the form with the "valid" input, form.validate_on_submit() always fail.
What I can't understand is that even when I try to print array errors, no error shows.
What am I missing?
There are a few issues here. Firstly, in your html, you haven't set a method attribute for the form. This means that it defaults to GET, which is why the form isn't validating. This can be changed like so:
<form action="{{ url_for('register') }}" method='POST'>
Incidentally, as the view that loads the form is the same as the target, you can leave out the action attribute, giving us:
<form method='POST'>
Secondly, in your class, you have a couple of issues with the confirm_password field. Firstly, you have a typo in PasswordField('confirm passord'. Secondly, the EqualTo() validator expects a string, not a field. We need to change this line in full to:
confirm_password = PasswordField('confirm password', validators=[InputRequired(), Length(min=6), EqualTo('password')])
Finally, in your flask, we need to accept POST requests to the view. This can be done by altering #app.route():
#app.route('/register', methods=['POST', 'GET'])
Having made these changes, the form should work as expected.
I'm not sure where I'm going wrong with the form validation... I also want to display error messages wether the for was submitted successfully or not.
Currently, I'm using a DetailView, where a person can fill in a BookingForm()
forms.py
from django.core.validators import RegexValidator
class BookingForm(forms.Form):
Name = forms.CharField()
Postcode = forms.CharField(max_length=8,label='Postcode')
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
Phone = forms.CharField(max_length=15,validators=[phone_regex],label='Phone')
Date = forms.CharField(max_length=30,label='Date')
Time = forms.CharField(max_length=10,label='Time')
In my views.py I defined def post to allow post requests. However, I always get the ELSE loop returned
def post(self,request,**kwargs):
# put your own credentials here
form = BookingForm(self.request.POST)
if form.is_valid():
user_phone = form.cleaned_data['Phone']
postcode = form.cleaned_data['Postcode']
date = form.cleaned_data['Date']
account_sid = "***"
auth_token = "***"
found = Model.objects.get(id=self.kwargs['pk'])
client = Client(account_sid, auth_token)
client.messages.create(
to=Model.phone_number,
from_="+442033225719",
body="You have a new booking." +
"Call phone number:{}. Address: {}. Date:{}"
.format(user_phone,postcode,date))
messages.success(request, 'Your booking was reserved.')
else:
messages.error(request, 'Error occurred.')
return redirect('users:detail', pk=self.kwargs['pk'])
And my model_detail.html which handles the form.
FURTHER EDIT:
I created the following HTML template which I include in the main template using {% include 'booking_form.html' %}:
<!-- Book Now -->
<form action="" method="post">
{{ form.non_field_errors }}
{% csrf_token %}
<div class="boxed-widget">
<h3><i class="fa fa-calendar-check-o "></i> Book Now</h3>
<div class="row with-forms margin-top-0">
<div class="col-lg-6 col-md-12">
{{ form.name.errors }}
<label for="{{ form.name.id_for_label }}">Full Name:</label>
{{ form.name }}
</div>
<div class="col-lg-6 col-md-12">
{{ form.postcode.errors }}
<label for="{{ form.postcode.id_for_label }}">Postcode:</label>
{{ form.postcode }}
</div>
</div>
<div class="row with-forms margin-top-0">
<div class="col-lg-12 col-md-12">
{{ form.name.errors }}
<label for="{{ form.name.id_for_label }}">Full Name:</label>
{{ form.name }}
</div>
</div>
<div class="row with-forms margin-top-0">
<div class="col-lg-6 col-md-12">
{{ form.date.errors }}
<input name="Date" type="text" id="booking-date" data-lang="en" data-large-mode="true" data-min-year="2017" data-max-year="2020">
</div>
<div class="col-lg-6 col-md-12">
{{ form.time.errors }}
<input name="Time" type="text" id="booking-time" value="9:00 am">
</div>
</div>
<!-- progress button animation handled via custom.js -->
<button type="submit" class="progress-button button fullwidth margin-top-5"><span>Book Now</span></button>
</div>
</form>
<!-- Book Now / End -->
My BookingForm in forms.py has remained unchanged. However, now, I see no fields to input. I'm assuming this is because the form is not passed into the template.
Full content of my views.py of the DetailView:
class TeacherView(generic.DetailView,FormMixin):
model = Teacher
form_class = BookingForm
def post(self,request,**kwargs):
form = BookingForm(self.request.POST)
if form.is_valid():
user_phone = form.cleaned_data['Phone']
account_sid = "***"
auth_token = "***"
teacher = Teacher.objects.get(id=self.kwargs['pk'])
client = Client(account_sid, auth_token)
client.messages.create(
to=teacher.phone_number,
from_="+442033225719",
body=""
messages.success(request, 'Success Message')
return redirect('users:index')
else:
messages.error(request, 'Error occured.')
return redirect("users:index")
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(TeacherView, self).get_context_data(**kwargs)
# Add extra context from another model
context['form'] = self.get_form()
return context
You're always redirecting, whether the form is valid or not, so obviously you can't have the form errors displayed. If you want the form errors to be shown in your template, you need to render the template and return it as response when the validation fail - example with a plain function-based view (if you insist on using generic class-based views then use a FormMixin with your DetailView):
def myview(request, ...):
if request.method == "POST":
form = MyForm(request.POST):
if form.is_valid():
handle_the_form(...)
messages.success(request, "success message here")
return redirect(where you want to redirect)
else:
# GET, display an empty form
form = MyForm()
return render(request, "mytemplate.html", context={"form":form})
Also in your template you need to use the form itself instead of hardcoding it, as explained here in the FineManual.
wrt/ the messages framework's messages not displaying either, this is certainly a configuration issue, so re-read the messages doc and check your settings etc.
I am trying to authenticate users against an existing database. I can authenticate the user with their email and password combination but I cannot save the authorisation, meaning the user is not actually logged in.
I know this because in Template.html, it is not showing the correct options after login when I call {% if user and not user.is_anonymous %}
I believe the fault is coming from this line in views.py
auth_login(request, user)
Views.py
from django.contrib.auth import logout as auth_logout
from django.contrib.auth import login as auth_login
from django.contrib.auth import authenticate
...
def login_email(request):
if request.method == 'POST':
email = request.POST.get('email')
password = hashlib.md5(request.POST.get('password')).hexdigest()
#db query to check if email and password combination exist
user = Users.objects.get(email=email,password=password)
if user is not None:
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth_login(request, user)
return redirect('/personalised')
else: #failed to return to login page
return render(request, 'login.html',{})
#invalid POST request recieved
else:
return render(request,"login.html",{})
login.html
<form action="/login_email/" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="email">Email address</label>
<input type="email" name="email" class="form-control" id="email" placeholder="Email">
</div>
<div class="form-group">
<label for="email">Password</label>
<input type="password" name="password" class="form-control" id="password" placeholder="Password">
</div>
<button type="submit" class="btn btn-info">Submit</button>
</form>
Models.py
class Users(models.Model):
visitorid = models.CharField(db_column='visitorID', max_length=80) # Field name made lowercase.
name = models.CharField(max_length=255)
source = models.CharField(max_length=4)
visits = models.IntegerField()
last_visit = models.CharField(max_length=10)
email = models.CharField(max_length=255)
unsubscribe = models.CharField(max_length=1)
twitter = models.CharField(max_length=100)
password = models.TextField()
.....
template.py
{% if user and not user.is_anonymous %}
<li>My Feed </li>
<li>Trending</li>
<li>Your Saves</li>
<li>Logout </li>
{% else %}
<button type="button" class="btn btn-success navbar-btn">Sign in with Email</button>
{% endif %}
Do not use this code:
email = request.POST.get('email')
password = hashlib.md5(request.POST.get('password')).hexdigest()
#db query to check if email and password combination exist
user = Users.objects.get(email=email,password=password)
Instead use the authenticate method. It returns a User
user = authenticate(email=email, password=password)
This assumes that you have an appropriate auth backend setup.