diff --git a/app/templates/base.html b/app/templates/base.html
index 1f76832..2c0bc3a 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -18,7 +18,7 @@
- ZaPF-Auth
+ {{config["BRANDING"]}}
diff --git a/app/user/__init__.py b/app/user/__init__.py
index 880464b..d229c83 100644
--- a/app/user/__init__.py
+++ b/app/user/__init__.py
@@ -47,18 +47,6 @@ def login_required(f):
def wrapped(*args, **kwargs):
if not current_user or current_user.is_anonymous:
return redirect(url_for("user.login"))
- if not current_user.confirm_mail or not current_user.confirm_mail["confirmed"]:
- if current_user.confirm_mail and current_user.confirm_mail["token"]:
- flash("Your mail is not confirmed yet.", "warning")
- return redirect(url_for("user.confirm_mail_resend"))
- else:
- current_user.confirm_mail_start()
- flash(
- "Your mail is not confirmed yet. A confirmation mail has been sent now",
- "warning",
- )
- logout_user()
- return redirect(url_for("user.login"))
return f(*args, **kwargs)
return wrapped
diff --git a/app/user/admin.py b/app/user/admin.py
index 3fe75d2..e4b2b25 100644
--- a/app/user/admin.py
+++ b/app/user/admin.py
@@ -8,6 +8,7 @@
from . import groups_required, user_blueprint, login_required
from .models import User
from .views import MailInUseValidator
+from .helpers import UserEmailChangeRequest
class UserEditForm(FlaskForm):
@@ -100,9 +101,10 @@ def edit_user(username, back_url=None):
)
if not current_user.is_admin and old_mail != form.mail.data:
- user.confirm_mail_start()
+ UserEmailChangeRequest(user.username, form.mail.data)
flash(
- "E-Mail changed, new confirmation required. Check your mails", "warning"
+ "A confirmation email will be sent to your updated email address.",
+ "warning",
)
flash("User information changed", "success")
diff --git a/app/user/helpers.py b/app/user/helpers.py
index 8acc3bd..2d353a3 100644
--- a/app/user/helpers.py
+++ b/app/user/helpers.py
@@ -1,60 +1,168 @@
-from flask import current_app, url_for
+from flask import current_app, url_for, render_template, flash, redirect
from flask_mail import Message
-
-
-def send_password_reset_mail(user):
- msg = Message(
- "ZaPF-Auth-System: Passwort zurücksetzen",
- recipients=[user.mail],
- sender=current_app.config["MAIL_DEFAULT_SENDER"],
- )
- url = url_for(
- "user.reset_password_finish",
- username=user.username,
- token=user.reset_password[0],
- _external=True,
- )
-
- msg.body = """Hallo Benutzer "{0.username}",
-
-du kannst dein Passwort auf folgender Website zurücksetzen:
-
-{1}
-
-Der Link ist für 1 Tag gültig.
-
-Viele Grüße
-Dein ZaPF-Auth-System""".format(
- user, url
- )
-
- current_app.mail.send(msg)
-
-
-def send_confirm_mail(user):
- msg = Message(
- "ZaPF-Auth-System: E-Mail bestätigen",
- recipients=[user.mail],
- sender=current_app.config["MAIL_DEFAULT_SENDER"],
- )
- url = url_for(
- "user.confirm_mail_finish",
- username=user.username,
- token=user.confirm_mail["token"],
- _external=True,
- )
-
- msg.body = """Hallo Benutzer "{0.username}",
-
-um deine E-Mail zu bestätigen, gehe bitte auf folgende Website:
-
-{1}
-
-Der Link ist für 1 Tag gültig.
-
-Viele Grüße
-Dein ZaPF-Auth-System""".format(
- user, url
- )
-
- current_app.mail.send(msg)
+from .models import User
+
+
+class EmailConfirmation(object):
+ _confirm_mail_token = None
+ TOKEN_NAMESPACE = "confirm_mail"
+
+ @classmethod
+ def get(cls, token):
+ key = cls.cache_key(token)
+ print(key)
+ instance = current_app.cache.get(key)
+ return instance
+
+ @classmethod
+ def cache_key(cls, token):
+ return "user/{namespace}/{token}".format(
+ namespace=cls.TOKEN_NAMESPACE, token=token
+ )
+
+ def __init__(self, username, mail, subject, body):
+ self.subject = subject
+ self.body = body
+ self.send_mail(username, mail)
+ cache_key = self.cache_key(self.confirm_mail_token)
+ print(cache_key)
+ current_app.cache.set(cache_key, self)
+
+ @property
+ def confirm_mail_token(self):
+ if self._confirm_mail_token is None:
+ import secrets
+
+ self._confirm_mail_token = secrets.token_urlsafe(
+ current_app.config["CONFIRM_MAIL_TOKEN_LENGTH"]
+ )
+ return self._confirm_mail_token
+
+ def send_mail(self, username, mail):
+ msg = Message(
+ self.subject,
+ recipients=[mail],
+ sender=current_app.config["MAIL_DEFAULT_SENDER"],
+ )
+
+ msg.body = self.body
+
+ if current_app.config["MAIL_SUPPRESS_SEND"]:
+ # log mail instead
+ print(" * Would send the following mail:")
+ print(msg)
+
+ current_app.mail.send(msg)
+
+ def confirm(self):
+ raise NotImplementedError()
+
+
+class UserCreationRequest(EmailConfirmation):
+ """
+ Represents a user with an unconfirmed email. Not added to the LDAP yet, but
+ saved in the cache.
+ """
+
+ def __init__(self, username, password, mail, *args, **kwargs):
+ kwargs.update(
+ {
+ "username": username,
+ "password": password,
+ "mail": mail,
+ }
+ )
+
+ self.params = (args, kwargs)
+ subject = "{branding}: E-Mail bestätigen".format(
+ branding=current_app.config["BRANDING"]
+ )
+ url = url_for(
+ "user.confirm_mail_finish",
+ token=self.confirm_mail_token,
+ _external=True,
+ )
+ body = render_template(
+ "confirm_mail.j2",
+ username=username,
+ url=url,
+ branding=current_app.config["BRANDING"],
+ )
+ super(UserCreationRequest, self).__init__(username, mail, subject, body)
+
+ def confirm(self):
+ User.create(*self.params[0], **self.params[1])
+ flash("Your user account has been created!", "success")
+ return redirect("/")
+
+
+class UserEmailChangeRequest(EmailConfirmation):
+ def __init__(self, username, mail):
+ self.username = username
+ self.mail = mail
+ subject = "{branding}: E-Mail bestätigen".format(
+ branding=current_app.config["BRANDING"]
+ )
+
+ url = url_for(
+ "user.confirm_mail_finish",
+ token=self.confirm_mail_token,
+ _external=True,
+ )
+
+ body = render_template(
+ "confirm_mail.j2",
+ username=username,
+ url=url,
+ branding=current_app.config["BRANDING"],
+ )
+ super(UserEmailChangeRequest, self).__init__(username, mail, subject, body)
+
+ def confirm(self):
+ user = User.get(self.username)
+
+ if not user:
+ raise Exception("Invalid user in email change request!")
+
+ user.mail = self.mail
+ user.save()
+ flash("E-Mail confirmed", "success")
+ return redirect("/")
+
+
+class PasswordResetRequest(EmailConfirmation):
+ TOKEN_NAMESPACE = "reset_password"
+
+ def __init__(self, username):
+ self._user = None
+ self.username = username
+ subject = "{branding}: Passwort zurücksetzen".format(
+ branding=current_app.config["BRANDING"]
+ )
+ url = url_for(
+ "user.reset_password_finish",
+ token=self.confirm_mail_token,
+ _external=True,
+ )
+
+ body = render_template(
+ "password_reset_mail.j2",
+ username=username,
+ url=url,
+ branding=current_app.config["BRANDING"],
+ )
+ super(PasswordResetRequest, self).__init__(
+ username, self.user.mail, subject, body
+ )
+
+ @property
+ def user(self):
+ if not self._user:
+ self._user = User.get(self.username)
+ return self._user
+
+ def confirm(self, password):
+ self.user.password = password
+ self.user.save()
+ flash("New password has been set.", "info")
+ return redirect(url_for("user.login"))
diff --git a/app/user/models.py b/app/user/models.py
index b6fa1f4..6dd21b7 100644
--- a/app/user/models.py
+++ b/app/user/models.py
@@ -4,11 +4,8 @@
import time
from flask_login import UserMixin, AnonymousUserMixin
from flask import current_app
-
from app.orm import LDAPOrm
-from .helpers import send_password_reset_mail, send_confirm_mail
-
class AnonymousUser(AnonymousUserMixin):
@property
@@ -40,8 +37,6 @@ def __init__(self, username=None, dn=None, firstName=None, surname=None, mail=No
self._full_name = None
self._password = None
self.mail = mail
- self.reset_password = None
- self.confirm_mail = None
# FIXME: This could be simplified to just create a User object, populate it,
@staticmethod
@@ -126,7 +121,6 @@ def _orm_mapping_load(self, entry):
self.surname = entry.sn.value
self._full_name = entry.cn.value
self.mail = entry.mail.value
- self.data = entry.description.value
def _orm_mapping_save(self, entry):
# FIXME: It would be nice if the ORM could somehow automagically
@@ -134,7 +128,6 @@ def _orm_mapping_save(self, entry):
entry.sn = self.surname
entry.cn = self.full_name
entry.givenName = self.firstName
- entry.description = self.data
if self.password:
entry.userPassword = self._password
if self.mail:
@@ -152,40 +145,6 @@ def full_name(self):
firstName=self.firstName, surname=self.surname
)
- @property
- def data(self):
- return json.dumps(
- {"confirm_mail": self.confirm_mail, "reset_password": self.reset_password}
- )
-
- @data.setter
- def data(self, value):
- try:
- jsonData = json.loads(value)
- except:
- self.confirm_mail = None
- self.reset_password = None
- return
- self.confirm_mail = jsonData["confirm_mail"]
- self.reset_password = jsonData["reset_password"]
-
- def reset_password_start(self):
- self.reset_password = (
- binascii.hexlify(os.urandom(20)).decode("ascii"),
- int(time.time()) + 24 * 60 * 60,
- )
- send_password_reset_mail(self)
- self.save()
-
- def confirm_mail_start(self):
- self.confirm_mail = {
- "confirmed": False,
- "token": binascii.hexlify(os.urandom(20)).decode("ascii"),
- "valid_till": int(time.time()) + 24 * 60 * 60,
- }
- send_confirm_mail(self)
- self.save()
-
class Group(LDAPOrm):
# This doesn't really work either, so we have to overload _basedn
diff --git a/app/user/templates/confirm_mail.j2 b/app/user/templates/confirm_mail.j2
new file mode 100644
index 0000000..3bb7046
--- /dev/null
+++ b/app/user/templates/confirm_mail.j2
@@ -0,0 +1,10 @@
+Hallo {{username}},
+
+um deine E-Mail zu bestätigen, gehe bitte auf folgende Website:
+
+{{url}}
+
+Der Link ist für 1 Tag gültig.
+
+Viele Grüße
+Dein {{branding}}
\ No newline at end of file
diff --git a/app/user/templates/password_reset_mail.j2 b/app/user/templates/password_reset_mail.j2
new file mode 100644
index 0000000..8a984ef
--- /dev/null
+++ b/app/user/templates/password_reset_mail.j2
@@ -0,0 +1,10 @@
+Hallo {{username}},
+
+du kannst dein Passwort auf folgender Website zurücksetzen:
+
+{{ url }}
+
+Der Link ist für 1 Tag gültig.
+
+Viele Grüße
+Dein {{ branding }}
\ No newline at end of file
diff --git a/app/user/views.py b/app/user/views.py
index 9fe2c72..daceb30 100644
--- a/app/user/views.py
+++ b/app/user/views.py
@@ -10,6 +10,7 @@
import time
from app.views import is_safe_url, get_redirect_target
from . import login_required
+from .helpers import UserCreationRequest, UserEmailChangeRequest, PasswordResetRequest
class UsernameInUseValidator(object):
@@ -98,10 +99,6 @@ class PasswordResetFinishForm(FlaskForm):
submit = SubmitField("Set new password")
-class ResendConfirmMailForm(FlaskForm):
- submit = SubmitField("Resend confirmation mail")
-
-
@user_blueprint.route("/")
@login_required
def home():
@@ -131,17 +128,17 @@ def login():
def signup():
form = SignUpForm()
if form.validate_on_submit():
- user = User.create(
+ UserCreationRequest(
username=form.username.data,
password=form.password.data,
givenName=form.givenName.data,
surname=form.surname.data,
mail=form.mail.data,
)
- user.confirm_mail_start()
- current_app.logger.info("creating user: {}".format(user))
- flash("Your user account has been created.", "info")
- flash("Your E-Mail has to be confirmed before you can login!", "warning")
+ flash(
+ "Your E-Mail has to be confirmed before your user account is created!",
+ "warning",
+ )
return form.redirect()
return render_template("/signup.html", form=form)
@@ -180,7 +177,8 @@ def reset_password_start():
if len(users) > 0:
user = users[0]
if user:
- user.reset_password_start()
+ PasswordResetRequest(username=user.username)
+
flash(
"If your username or mail is valid, you should recive a mail with instructions soon!",
"info",
@@ -189,66 +187,30 @@ def reset_password_start():
return render_template("reset_password_start.html", form=form)
-@user_blueprint.route(
- "/user/reset_password//", methods=["GET", "POST"]
-)
-def reset_password_finish(username, token):
- user = User.get(username)
-
- if not user:
+@user_blueprint.route("/user/reset_password/", methods=["GET", "POST"])
+def reset_password_finish(token):
+ valid_request = PasswordResetRequest.get(token)
+ print(valid_request)
+ if not valid_request:
+ flash("Invalid token!")
return redirect(url_for("user.login"))
- if (
- not user.reset_password
- or user.reset_password[0] != token
- or user.reset_password[1] < int(time.time())
- ):
- flash("Your password reset token is invalid or expired.", "error")
- return redirect(url_for("user.home"))
form = PasswordResetFinishForm()
if form.validate_on_submit():
- user.password = form.password.data
- user.reset_password = None
- user.save()
- flash("New password has been set.", "info")
- return redirect(url_for("user.login"))
+ return valid_request.confirm(form.password.data)
return render_template("reset_password_finish.html", form=form)
-@user_blueprint.route("/user/confirm_mail", methods=["GET", "POST"])
-@flask_login.login_required
-def confirm_mail_resend():
- form = ResendConfirmMailForm()
- if form.validate_on_submit():
- current_user.confirm_mail_start()
- logout_user()
- return redirect(url_for("user.login"))
- return render_template("resend_confirm_mail.html", form=form)
-
-
-@user_blueprint.route(
- "/user/confirm_mail//", methods=["GET", "POST"]
-)
-def confirm_mail_finish(username, token):
- user = User.get(username)
-
- if not user:
- return redirect(url_for("user.login"))
- if (
- not user.confirm_mail
- or user.confirm_mail["token"] != token
- or user.confirm_mail["valid_till"] < int(time.time())
- ):
- flash("Your mail confirmation token is invalid or expired.", "error")
+@user_blueprint.route("/user/confirm_mail/", methods=["GET", "POST"])
+def confirm_mail_finish(token):
+ confirmation_request = current_app.cache.get(
+ "user/confirm_mail/{token}".format(token=token)
+ )
+ print(confirmation_request)
+ if not confirmation_request:
+ flash("Invalid token!")
return redirect(url_for("user.login"))
- user.confirm_mail["confirmed"] = True
- user.confirm_mail["token"] = None
- user.confirm_mail["valid_till"] = None
- user.save()
-
- flash("E-Mail confirmed", "success")
-
- return redirect("/")
+ return confirmation_request.confirm()
diff --git a/config.py b/config.py
index 05818ad..b2c77db 100644
--- a/config.py
+++ b/config.py
@@ -6,6 +6,7 @@
class Config:
FLASK_COVERAGE = 0
MOCKSERVER = False
+ BRANDING = "Auth"
LDAP_HOST = "localhost"
LDAP_PORT = 8369
LDAP_BASE_DN = "dc=my-domain,dc=com"
@@ -34,8 +35,7 @@ class Config:
]
MAIL_USE_TLS = True
- MAIL_DEFAULT_SENDER = "topf@zapf.in"
- MAIL_NEXT_ZAPF_ORGA = "topf@zapf.in"
+ MAIL_DEFAULT_SENDER = "mail@example.com"
CACHE_TYPE = "simple"
@@ -44,18 +44,30 @@ class Config:
PASSWORD_HASHING_FUNC = ldap3.HASHED_SALTED_SHA384
+ CONFIRM_MAIL_TOKEN_LENGTH = 20
+
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
+ print(" * Using development config!")
+
SECRET_KEY = "secrets"
DEBUG = True
RECAPTCHA_PUBLIC_KEY = "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
RECAPTCHA_PRIVATE_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
RECAPTCHA_USE_SSL = False
+
+ LDAP_BASE_DN = "dc=example,dc=com"
+ LDAP_BIND_USER_DN = "uid=auth,dc=example,dc=com"
+ LDAP_BIND_USER_PASSWORD = "test"
+ import ldap3
+
+ PASSWORD_HASHING_FUNC = ldap3.HASHED_SALTED_SHA
# MOCKSERVER = True
+ MAIL_SUPPRESS_SEND = True
class ProductionConfig(Config):
diff --git a/docker-compose.yml b/docker-compose.yml
index 9f1e8f5..a71e101 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,8 +3,8 @@ services:
openldap:
image: osixia/openldap
environment:
- LDAP_ORGANISATION: "ZaPF"
- LDAP_DOMAIN: "zapf.in"
+ LDAP_ORGANISATION: "Example Org."
+ LDAP_DOMAIN: "example.com"
LDAP_BACKEND: "mdb"
expose:
- "389"
@@ -22,9 +22,9 @@ services:
command: --copy-service
auth:
build: .
- image: zapf-auth:latest
+ image: auth:latest
ports:
- - "80"
+ - "5000:80"
volumes:
- type: bind
source: ./docker/auth.conf
diff --git a/docker.md b/docker.md
index b43b6c8..b90fb42 100644
--- a/docker.md
+++ b/docker.md
@@ -13,7 +13,7 @@ An OpenLDAP server is provided using the [osixia/openldap] docker image.
**Make sure to change the passwords for the following default accounts:**
-The admin DN for the main tree at `dc=zapf,dc=in` is `cn=admin,dc=zapf,dc=in`
+The admin DN for the main tree at `dc=example,dc=com` is `cn=admin,dc=example,dc=com`
with the password specified in `LDAP_ADMIN_PASSWORD` environment variable.
This defaults to `admin`.
@@ -21,7 +21,7 @@ The admin DN for the config tree at `cn=config` is `cn=admin,cn=config` with
the password specified in `LDAP_CONFIG_PASSWORD`.
This defaults to `config`.
-The bind user for the auth application is `uid=zapf-auth,dc=zapf,dc=in`.
+The bind user for the auth application is `uid=auth,dc=example,dc=com`.
The password is specified in the
[`docker/bootstrap_openldap/ldif/bootstrap.ldif`] file.
This defaults to `test`.
@@ -29,8 +29,8 @@ When changing this password, hash it using `slappasswd`.
### Tree Structure
-The OU entries for `ou=people,dc=zapf,dc=in`, `ou=groups,dc=zapf,dc=in` and
-`ou=oauth,dc=zapf,dc=in` are created on startup.
+The OU entries for `ou=people,dc=example,dc=com`, `ou=groups,dc=example,dc=com` and
+`ou=oauth,dc=example,dc=com` are created on startup.
## App configuration
@@ -46,8 +46,8 @@ BOOTSTRAP_SERVE_LOCAL = True
# LDAP
LDAP_HOST = 'openldap'
LDAP_PORT = 389
-LDAP_BASE_DN = 'dc=zapf,dc=in'
-LDAP_BIND_USER_DN = 'uid=zapf-auth,dc=zapf,dc=in'
+LDAP_BASE_DN = 'dc=example,dc=com'
+LDAP_BIND_USER_DN = 'uid=auth,dc=example,dc=com'
LDAP_BIND_USER_PASSWORD = 'test'
import ldap3
PASSWORD_HASHING_FUNC = ldap3.HASHED_SALTED_SHA
@@ -62,7 +62,7 @@ MAIL_SERVER='smtp.example.org'
MAIL_PORT=465
MAIL_USE_TLS = False
MAIL_USE_SSL=True
-MAIL_USERNAME='zapf-auth-sender'
+MAIL_USERNAME='auth-sender'
MAIL_PASSWORD='CHANGEME'
# To prevent open redirects in OAuth logout
diff --git a/docker/bootstrap_openldap/acl.ldif b/docker/bootstrap_openldap/acl.ldif
index 3ea6a79..ab70e32 100644
--- a/docker/bootstrap_openldap/acl.ldif
+++ b/docker/bootstrap_openldap/acl.ldif
@@ -5,9 +5,9 @@ delete: olcAccess
add: olcAccess
olcAccess: {0}to dn.exact="" by * read
olcAccess: {1}to dn.base="cn=Subschema" by * read
-olcAccess: {2}to attrs=userpassword by self =xw by dn.base="uid=zapf-auth,dc=zapf,dc=in" break by anonymous auth by * none
-olcAccess: {3}to dn.subtree="ou=users,dc=zapf,dc=in" by self write by dn.base="uid=zapf-auth,dc=zapf,dc=in" write by dn.subtree="ou=users,dc=zapf,dc=in" search
-olcAccess: {4}to dn.children="ou=groups,dc=zapf,dc=in" attrs=cn,entry by dn.base="uid=zapf-auth,dc=zapf,dc=in" break by dnattr=member read
-olcAccess: {5}to dn.subtree="ou=groups,dc=zapf,dc=in" by dn.base="uid=zapf-auth,dc=zapf,dc=in" write by dn.subtree="ou=users,dc=zapf,dc=in" search
-olcAccess: {6}to dn.subtree="ou=oauth2,dc=zapf,dc=in" by dn.base="uid=zapf-auth,dc=zapf,dc=in" write
-olcAccess: {7}to dn.subtree="dc=zapf,dc=in" by dn.base="uid=zapf-auth,dc=zapf,dc=in" search
+olcAccess: {2}to attrs=userpassword by self =xw by dn.base="uid=auth,dc=example,dc=com" break by anonymous auth by * none
+olcAccess: {3}to dn.subtree="ou=users,dc=example,dc=com" by self write by dn.base="uid=auth,dc=example,dc=com" write by dn.subtree="ou=users,dc=example,dc=com" search
+olcAccess: {4}to dn.children="ou=groups,dc=example,dc=com" attrs=cn,entry by dn.base="uid=auth,dc=example,dc=com" break by dnattr=member read
+olcAccess: {5}to dn.subtree="ou=groups,dc=example,dc=com" by dn.base="uid=auth,dc=example,dc=com" write by dn.subtree="ou=users,dc=example,dc=com" search
+olcAccess: {6}to dn.subtree="ou=oauth2,dc=example,dc=com" by dn.base="uid=auth,dc=example,dc=com" write
+olcAccess: {7}to dn.subtree="dc=example,dc=com" by dn.base="uid=auth,dc=example,dc=com" search
diff --git a/docker/bootstrap_openldap/ldif/bootstrap.ldif b/docker/bootstrap_openldap/ldif/bootstrap.ldif
index 2647d3b..bc89146 100644
--- a/docker/bootstrap_openldap/ldif/bootstrap.ldif
+++ b/docker/bootstrap_openldap/ldif/bootstrap.ldif
@@ -1,25 +1,25 @@
-dn: uid=zapf-auth,dc=zapf,dc=in
+dn: uid=auth,dc=example,dc=com
changetype: add
-uid: zapf-auth
+uid: auth
objectClass: top
objectClass: simpleSecurityObject
objectClass: account
description: Bind user for ZaPF-Auth
userPassword: {SSHA}98H1A4YLoIZaceCtVoXIekAalnwlFsQd
-dn: ou=groups,dc=zapf,dc=in
+dn: ou=groups,dc=example,dc=com
changetype: add
objectClass: organizationalUnit
ou: groups
description: Automagically added by quasisentient sanity checks
-dn: ou=users,dc=zapf,dc=in
+dn: ou=users,dc=example,dc=com
changetype: add
objectClass: organizationalUnit
ou: users
description: Automagically added by quasisentient sanity checks
-dn: ou=oauth2,dc=zapf,dc=in
+dn: ou=oauth2,dc=example,dc=com
changetype: add
objectClass: organizationalUnit
ou: oauth2
diff --git a/docker/test.conf b/docker/test.conf
index 1e9c3e6..2ea69c8 100644
--- a/docker/test.conf
+++ b/docker/test.conf
@@ -5,8 +5,8 @@ BOOTSTRAP_SERVE_LOCAL = True
# LDAP
LDAP_HOST = 'openldap'
LDAP_PORT = 389
-LDAP_BASE_DN = 'dc=zapf,dc=in'
-LDAP_BIND_USER_DN = 'uid=zapf-auth,dc=zapf,dc=in'
+LDAP_BASE_DN = 'dc=example,dc=com'
+LDAP_BIND_USER_DN = 'uid=auth,dc=example,dc=com'
LDAP_BIND_USER_PASSWORD = 'test'
import ldap3
PASSWORD_HASHING_FUNC = ldap3.HASHED_SALTED_SHA
@@ -21,7 +21,7 @@ MAIL_SERVER='smtp.example.org'
MAIL_PORT=465
MAIL_USE_TLS = False
MAIL_USE_SSL=True
-MAIL_USERNAME='zapf-auth-sender'
+MAIL_USERNAME='auth-sender'
MAIL_PASSWORD='CHANGEME'
# To prevent open redirects in OAuth logout
diff --git a/manage.py b/manage.py
index 4fccdd6..a2fdda6 100755
--- a/manage.py
+++ b/manage.py
@@ -4,7 +4,7 @@
from flask_migrate import Migrate, MigrateCommand
from app.db import db
-app = create_app()
+app = create_app("development")
manager = Manager(app)
migrate = Migrate(app, db)