Skip to content

Commit

Permalink
Log in using ldap.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Skiepko committed May 16, 2017
1 parent 9dd2172 commit db954ea
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 8 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
Changelog for dila
=================

0.3.1 (unreleased)
0.4.0 (unreleased)
------------------

- Add login page using ldap backend.
- Preserve PO metadata.


Expand Down
2 changes: 1 addition & 1 deletion dila-development-compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ db:
POSTGRES_USER: dila
POSTGRES_PASSWORD: dila
ldap:
image: osixia/openldap:1.1.3
image: osixia/openldap:1.1.8
volumes:
- ../acceptance_tests/test.ldif:/scripts/test.ldif:ro
environment:
Expand Down
23 changes: 21 additions & 2 deletions dila/frontend/flask/authenticate_views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import flask
from cached_property import cached_property
from flask import views

from dila.frontend.flask import template_tools
from dila.frontend.flask import forms

blueprint = flask.Blueprint('authenticate', __name__)
template_tools.setup_language_context(blueprint)


class LoginView(views.MethodView):
def get(self):
return flask.render_template('login.html', **self.context)

def post(self):
if self.form.validate():
username = self.form.username.data
flask.session['username'] = username
return flask.redirect(flask.url_for('main.home'))
else:
return self.get()


@property
def context(self):
return {
'form': self.form,
}

@cached_property
def form(self):
return forms.LoginForm()


blueprint.add_url_rule('/login/', view_func=LoginView.as_view('login'))
13 changes: 13 additions & 0 deletions dila/frontend/flask/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,16 @@ class NewLanguageForm(flask_wtf.FlaskForm):
new_language_name = wtforms.StringField('New language')
new_language_short = wtforms.StringField('Language code')
next = wtforms.HiddenField()


class LoginForm(flask_wtf.FlaskForm):
username = wtforms.StringField('Username')
password = wtforms.PasswordField('Password')

def validate(self, *args, **kwargs):
if super().validate(*args, **kwargs):
if application.authenticate(self.username.data, self.password.data):
return True
else:
self.password.errors.append('Invalid login or password')
return False
1 change: 1 addition & 0 deletions dila/frontend/flask/template_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def static_url(filename):
return urllib.parse.urljoin(config.STATIC_URL, filename)
return flask.url_for('static', filename=filename)


def setup_language_context(blueprint):
@blueprint.context_processor
def inject_languages_menu():
Expand Down
28 changes: 25 additions & 3 deletions dila/frontend/flask/templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@
<![endif]-->
</head>
<body style="padding-top: 50px">

<div class="container">
Log in.
<form method="POST" action="{{ url_for('authenticate.login') }}" enctype=multipart/form-data>
{{ form.csrf_token }}
<div class="form-group">
{{ form.username.label }} {{ form.username(class_="form-control") }}
{% if form.username.errors %}
<ul class="help-block">
{% for error in form.username.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="form-group">
{{ form.password.label }} {{ form.password(class_="form-control") }}
{% if form.password.errors %}
<ul class="help-block">
{% for error in form.password.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<input class="btn btn-primary" id="login" value="Log in" type="submit">
</form>
</div>
<script src="{{ static_url('vendor/js/jquery.min.js') }}"></script>
<script src="{{ static_url('vendor/js/bootstrap.min.js') }}"></script>
</body>
</html>
</html>
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setup(
name='dila',
version='0.3.1.dev0',
version='0.4.0.dev0',
description='Dila is a open source web-based translation platform for translators, content creators and developers.',
author='Jakub Skiepko',
author_email='[email protected]',
Expand Down
1 change: 1 addition & 0 deletions test_image/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM python:3.6
RUN apt-get update && apt-get install -y libldap2-dev libsasl2-dev && rm -rf /var/lib/apt/lists/*
COPY base_requirements.txt /package/
RUN pip install -r /package/base_requirements.txt
COPY dila /package/dila
Expand Down
2 changes: 2 additions & 0 deletions test_image/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
LDAP_SERVER_URI = 'ldap://ldap'
LDAP_BIND_DN = 'cn=admin,dc=example,dc=com'
LDAP_BIND_PASSWORD = 'admin_password'
LDAP_BASE_DN = 'ou=employees,dc=example,dc=com'
LDAP_USER_OBJECT_FILTER = "(|(uid=%(user)s)(mail=%(user)s))"
28 changes: 28 additions & 0 deletions tests/test_authentication_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import re
from unittest import mock


def test_login_form(flask_client):
response = flask_client.get('/login/')
assert re.search('<input class="[^"]*" id="username" name="username" type="text" value="">',
response.data.decode())
assert re.search('<input class="[^"]*" id="password" name="password" type="password" value="">',
response.data.decode())
assert re.search('<input class="[^"]*" id="login" value="Log in" type="submit">', response.data.decode())


@mock.patch('dila.application.authenticate')
def test_post_login(authenticate, flask_client):
authenticate.return_value = True
response = flask_client.post('/login/', data={'username': 'songo', 'password': 'ssj4'})
authenticate.assert_called_once_with('songo', 'ssj4')
assert response.status_code == 302
assert response.location == 'http://localhost/'


@mock.patch('dila.application.authenticate')
def test_post_invalid_login(authenticate, flask_client):
authenticate.return_value = False
response = flask_client.post('/login/', data={'username': 'songo', 'password': 'ssj5'})
authenticate.assert_called_once_with('songo', 'ssj5')
assert "Invalid login or password" in response.data.decode()

0 comments on commit db954ea

Please sign in to comment.