Merge pull request #1 from Krakinou/flaskldap

Flaskldap integration
pull/769/head
Krakinou 6 years ago committed by GitHub
commit 6190e64956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -164,16 +164,58 @@
{% endif %} {% endif %}
<div class="form-group"> <div class="form-group">
<input type="checkbox" id="config_use_ldap" name="config_use_ldap" data-control="ldap-settings" {% if content.config_use_ldap %}checked{% endif %}> <input type="checkbox" id="config_use_ldap" name="config_use_ldap" data-control="ldap-settings" {% if content.config_use_ldap %}checked{% endif %}>
<label for="config_use_ldap">{{_('Use')}} LDAP Authentication</label> <label for="config_use_ldap">{{_('Use LDAP Authentication')}}</label>
</div> </div>
<div data-related="ldap-settings"> <div data-related="ldap-settings">
<div class="form-group"> <div class="form-group">
<label for="config_ldap_provider_url">{{_('LDAP Provider URL')}}</label> <label for="config_ldap_provider_url">{{_('LDAP Server Host Name or IP Address')}}</label>
<input type="text" class="form-control" id="config_ldap_provider_url" name="config_ldap_provider_url" value="{% if content.config_use_ldap != None %}{{ content.config_ldap_provider_url }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_ldap_provider_url" name="config_ldap_provider_url" value="{% if content.config_ldap_provider_url != None %}{{ content.config_ldap_provider_url }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_ldap_port">{{_('LDAP Server Port')}}</label>
<input type="text" class="form-control" id="config_ldap_port" name="config_ldap_port" value="{% if content.config_ldap_port != None %}{{ content.config_ldap_port }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_ldap_schema">{{_('LDAP schema (ldap or ldaps)')}}</label>
<input type="text" class="form-control" id="config_ldap_schema" name="config_ldap_schema" value="{% if content.config_ldap_schema != None %}{{ content.config_ldap_schema }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_ldap_serv_username">{{_('LDAP Admin username')}}</label>
<input type="text" class="form-control" id="config_ldap_serv_username" name="config_ldap_serv_username" value="{% if content.config_ldap_serv_username != None %}{{ content.config_ldap_serv_username }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_ldap_serv_password">{{_('LDAP Admin password')}}</label>
<input type="password" class="form-control" id="config_ldap_serv_password" name="config_ldap_serv_password" value="{% if content.config_ldap_serv_password != None %}{{ content.config_ldap_serv_password }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<input type="checkbox" id="config_ldap_use_ssl" name="config_ldap_use_ssl" {% if content.config_ldap_use_ssl %}checked{% endif %}>
<label for="config_ldap_ssl">{{_('LDAP Server use SSL')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_ldap_use_tls" name="config_ldap_use_tls" {% if content.config_ldap_use_tls %}checked{% endif %}>
<label for="config_ldap_ssl">{{_('LDAP Server use TLS')}}</label>
</div>
<div class="form-group">
<input type="checkbox" id="config_ldap_require_cert" name="config_ldap_require_cert" data-control="ldap-cert-settings" {% if content.config_ldap_require_cert %}checked{% endif %}>
<label for="config_ldap_ssl">{{_('LDAP Server Certificate')}}</label>
</div>
<div data-related="ldap-cert-settings">
<div class="form-group">
<label for="config_ldap_cert_path">{{_('LDAP SSL Certificate Path')}}</label>
<input type="text" class="form-control" id="config_ldap_cert_path" name="config_ldap_cert_path" value="{% if content.config_ldap_cert_path != None and content.config_ldap_require_cert !=None %}{{ content.config_ldap_cert_path }}{% endif %}" autocomplete="off">
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="config_ldap_dn">{{_('LDAP Distinguished Name (DN)')}}</label> <label for="config_ldap_dn">{{_('LDAP Distinguished Name (DN)')}}</label>
<input type="text" class="form-control" id="config_ldap_dn" name="config_ldap_dn" value="{% if content.config_use_ldap != None %}{{ content.config_ldap_dn }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_ldap_dn" name="config_ldap_dn" value="{% if content.config_ldap_dn != None %}{{ content.config_ldap_dn }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_ldap_user_object">{{_('LDAP User object filter')}}</label>
<input type="text" class="form-control" id="config_ldap_user_object" name="config_ldap_user_object" value="{% if content.config_ldap_user_object != None %}{{ content.config_ldap_user_object }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<input type="checkbox" id="config_ldap_openldap" name="config_ldap_openldap" {% if content.config_ldap_openldap %}checked{% endif %}>
<label for="config_ldap_openldap">{{_('LDAP Server is OpenLDAP?')}}</label>
</div> </div>
</div> </div>
</div> </div>

@ -148,14 +148,6 @@ class UserBase:
def __repr__(self): def __repr__(self):
return '<User %r>' % self.nickname return '<User %r>' % self.nickname
#Login via LDAP method
@staticmethod
def try_login(username, password):
conn = get_ldap_connection()
conn.simple_bind_s(
config.config_ldap_dn.replace("%s", username),
password
)
# Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from # Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from
# User Base (all access methods are declared there) # User Base (all access methods are declared there)
@ -315,8 +307,18 @@ class Settings(Base):
config_goodreads_api_key = Column(String) config_goodreads_api_key = Column(String)
config_goodreads_api_secret = Column(String) config_goodreads_api_secret = Column(String)
config_use_ldap = Column(Boolean) config_use_ldap = Column(Boolean)
config_ldap_provider_url = Column(String) config_ldap_provider_url = Column(String, default='localhost')
config_ldap_port = Column(SmallInteger, default=389)
config_ldap_schema = Column(String, default='ldap')
config_ldap_serv_username = Column(String)
config_ldap_serv_password = Column(String)
config_ldap_use_ssl = Column(Boolean, default=False)
config_ldap_use_tls = Column(Boolean, default=False)
config_ldap_require_cert = Column(Boolean, default=False)
config_ldap_cert_path = Column(String)
config_ldap_dn = Column(String) config_ldap_dn = Column(String)
config_ldap_user_object = Column(String)
config_ldap_openldap = Column(Boolean)
config_mature_content_tags = Column(String) config_mature_content_tags = Column(String)
config_logfile = Column(String) config_logfile = Column(String)
config_ebookconverter = Column(Integer, default=0) config_ebookconverter = Column(Integer, default=0)
@ -392,7 +394,17 @@ class Config:
self.config_goodreads_api_secret = data.config_goodreads_api_secret self.config_goodreads_api_secret = data.config_goodreads_api_secret
self.config_use_ldap = data.config_use_ldap self.config_use_ldap = data.config_use_ldap
self.config_ldap_provider_url = data.config_ldap_provider_url self.config_ldap_provider_url = data.config_ldap_provider_url
self.config_ldap_port = data.config_ldap_port
self.config_ldap_schema = data.config_ldap_schema
self.config_ldap_serv_username = data.config_ldap_serv_username
self.config_ldap_serv_password = data.config_ldap_serv_password
self.config_ldap_use_ssl = data.config_ldap_use_ssl
self.config_ldap_use_tls = data.config_ldap_use_ssl
self.config_ldap_require_cert = data.config_ldap_require_cert
self.config_ldap_cert_path = data.config_ldap_cert_path
self.config_ldap_dn = data.config_ldap_dn self.config_ldap_dn = data.config_ldap_dn
self.config_ldap_user_object = data.config_ldap_user_object
self.config_ldap_openldap = data.config_ldap_openldap
if data.config_mature_content_tags: if data.config_mature_content_tags:
self.config_mature_content_tags = data.config_mature_content_tags self.config_mature_content_tags = data.config_mature_content_tags
else: else:
@ -680,9 +692,69 @@ def migrate_Database():
except exc.OperationalError: except exc.OperationalError:
conn = engine.connect() conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_use_ldap` INTEGER DEFAULT 0") conn.execute("ALTER TABLE Settings ADD column `config_use_ldap` INTEGER DEFAULT 0")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_provider_url)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_provider_url` String DEFAULT ''") conn.execute("ALTER TABLE Settings ADD column `config_ldap_provider_url` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_port)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_port` INTEGER DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_schema)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_schema ` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_serv_username)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_serv_username` String DEFAULT ''")
conn.execute("ALTER TABLE Settings ADD column `config_ldap_serv_password` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_use_ssl)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_use_ssl` INTEGER DEFAULT 0")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_use_tls)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `cconfig_ldap_use_tls` INTEGER DEFAULT 0")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_require_cert)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_require_cert` INTEGER DEFAULT 0")
conn.execute("ALTER TABLE Settings ADD column `config_ldap_cert_path` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_dn)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_dn` String DEFAULT ''") conn.execute("ALTER TABLE Settings ADD column `config_ldap_dn` String DEFAULT ''")
session.commit() session.commit()
try:
session.query(exists().where(Settings.config_ldap_user_object)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_user_object` String DEFAULT ''")
session.commit()
try:
session.query(exists().where(Settings.config_ldap_openldap)).scalar()
except exc.OperationalError:
conn = engine.connect()
conn.execute("ALTER TABLE Settings ADD column `config_ldap_openldap` INTEGER DEFAULT 0")
session.commit()
try: try:
session.query(exists().where(Settings.config_theme)).scalar() session.query(exists().where(Settings.config_theme)).scalar()
except exc.OperationalError: # Database is not compatible, some rows are missing except exc.OperationalError: # Database is not compatible, some rows are missing
@ -799,11 +871,6 @@ else:
migrate_Database() migrate_Database()
clean_database() clean_database()
#get LDAP connection
def get_ldap_connection():
import ldap
conn = ldap.initialize('ldap://{}'.format(config.config_ldap_provider_url))
return conn
# Generate global Settings Object accessible from every file # Generate global Settings Object accessible from every file
config = Config() config = Config()

@ -57,6 +57,7 @@ from redirect import redirect_back
import time import time
import server import server
from reverseproxy import ReverseProxied from reverseproxy import ReverseProxied
from __builtin__ import True
try: try:
from googleapiclient.errors import HttpError from googleapiclient.errors import HttpError
@ -107,6 +108,11 @@ try:
except ImportError: except ImportError:
from flask_login.__about__ import __version__ as flask_loginVersion from flask_login.__about__ import __version__ as flask_loginVersion
try:
from flask_simpleldap import LDAP, LDAPException
ldap_support = True
except ImportError:
ldap_support = False
# Global variables # Global variables
current_milli_time = lambda: int(round(time.time() * 1000)) current_milli_time = lambda: int(round(time.time() * 1000))
@ -176,6 +182,31 @@ lm.anonymous_user = ub.Anonymous
app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT') app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT')
db.setup_db() db.setup_db()
if ldap_support and config.config_use_ldap:
app.config['LDAP_HOST'] = config.config_ldap_provider_url
app.config['LDAP_PORT'] = config.config_ldap_port
app.config['LDAP_SCHEMA'] = config.config_ldap_schema
app.config['LDAP_USERNAME'] = config.config_ldap_user_object.replace('%s', config.config_ldap_serv_username) + ',' + config.config_ldap_dn
app.config['LDAP_PASSWORD'] = base64.b64decode(config.config_ldap_serv_password)
if config.config_ldap_use_ssl:
app.config['LDAP_USE_SSL'] = True
if config.config_ldap_use_tls:
app.config['LDAP_USE_TLS'] = True
app.config['LDAP_REQUIRE_CERT'] = config.config_ldap_require_cert
if config.config_ldap_require_cert:
app.config['LDAP_CERT_PATH'] = config.config_ldap_cert_path
app.config['LDAP_BASE_DN'] = config.config_ldap_dn
app.config['LDAP_USER_OBJECT_FILTER'] = config.config_ldap_user_object
if config.config_ldap_openldap:
app.config['LDAP_OPENLDAP'] = True
# app.config['LDAP_BASE_DN'] = 'ou=users,dc=yunohost,dc=org'
# app.config['LDAP_USER_OBJECT_FILTER'] = '(uid=%s)'
ldap = LDAP(app)
elif config.config_use_ldap and not ldap_support:
app.logger.error('Cannot activate ldap support, did you run \'pip install --target vendor -r optional-requirements-ldap.txt\'?')
with open(os.path.join(config.get_main_dir, 'cps/translations/iso639.pickle'), 'rb') as f: with open(os.path.join(config.get_main_dir, 'cps/translations/iso639.pickle'), 'rb') as f:
language_table = cPickle.load(f) language_table = cPickle.load(f)
@ -256,6 +287,13 @@ def requires_basic_auth_if_no_ano(f):
return decorated return decorated
def basic_auth_required_check(condition):
def decorator(f):
if condition and ldap_support:
return ldap.basic_auth_required(f)
return requires_basic_auth_if_no_ano(f)
return decorator
# simple pagination for the feed # simple pagination for the feed
class Pagination(object): class Pagination(object):
@ -690,31 +728,31 @@ def before_request():
# Routing functions # Routing functions
@app.route("/opds") @app.route("/opds")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_index(): def feed_index():
return render_xml_template('index.xml') return render_xml_template('index.xml')
@app.route("/opds/osd") @app.route("/opds/osd")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_osd(): def feed_osd():
return render_xml_template('osd.xml', lang='en-EN') return render_xml_template('osd.xml', lang='en-EN')
@app.route("/opds/search/<query>") @app.route("/opds/search/<query>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_cc_search(query): def feed_cc_search(query):
return feed_search(query.strip()) return feed_search(query.strip())
@app.route("/opds/search", methods=["GET"]) @app.route("/opds/search", methods=["GET"])
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_normal_search(): def feed_normal_search():
return feed_search(request.args.get("query").strip()) return feed_search(request.args.get("query").strip())
@app.route("/opds/new") @app.route("/opds/new")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_new(): def feed_new():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -723,7 +761,7 @@ def feed_new():
@app.route("/opds/discover") @app.route("/opds/discover")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_discover(): def feed_discover():
entries = db.session.query(db.Books).filter(common_filters()).order_by(func.random())\ entries = db.session.query(db.Books).filter(common_filters()).order_by(func.random())\
.limit(config.config_books_per_page) .limit(config.config_books_per_page)
@ -732,7 +770,7 @@ def feed_discover():
@app.route("/opds/rated") @app.route("/opds/rated")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_best_rated(): def feed_best_rated():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -741,7 +779,7 @@ def feed_best_rated():
@app.route("/opds/hot") @app.route("/opds/hot")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_hot(): def feed_hot():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by( all_books = ub.session.query(ub.Downloads, ub.func.count(ub.Downloads.book_id)).order_by(
@ -766,7 +804,7 @@ def feed_hot():
@app.route("/opds/author") @app.route("/opds/author")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_authorindex(): def feed_authorindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(common_filters())\ entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(common_filters())\
@ -777,7 +815,7 @@ def feed_authorindex():
@app.route("/opds/author/<int:book_id>") @app.route("/opds/author/<int:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_author(book_id): def feed_author(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -786,7 +824,7 @@ def feed_author(book_id):
@app.route("/opds/publisher") @app.route("/opds/publisher")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_publisherindex(): def feed_publisherindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\ entries = db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\
@ -797,7 +835,7 @@ def feed_publisherindex():
@app.route("/opds/publisher/<int:book_id>") @app.route("/opds/publisher/<int:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_publisher(book_id): def feed_publisher(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -807,7 +845,7 @@ def feed_publisher(book_id):
@app.route("/opds/category") @app.route("/opds/category")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_categoryindex(): def feed_categoryindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\ entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\
@ -818,7 +856,7 @@ def feed_categoryindex():
@app.route("/opds/category/<int:book_id>") @app.route("/opds/category/<int:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_category(book_id): def feed_category(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -827,7 +865,7 @@ def feed_category(book_id):
@app.route("/opds/series") @app.route("/opds/series")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_seriesindex(): def feed_seriesindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\ entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\
@ -838,7 +876,7 @@ def feed_seriesindex():
@app.route("/opds/series/<int:book_id>") @app.route("/opds/series/<int:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_series(book_id): def feed_series(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
@ -848,7 +886,7 @@ def feed_series(book_id):
@app.route("/opds/shelfindex/", defaults={'public': 0}) @app.route("/opds/shelfindex/", defaults={'public': 0})
@app.route("/opds/shelfindex/<string:public>") @app.route("/opds/shelfindex/<string:public>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_shelfindex(public): def feed_shelfindex(public):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
if public is not 0: if public is not 0:
@ -863,7 +901,7 @@ def feed_shelfindex(public):
@app.route("/opds/shelf/<int:book_id>") @app.route("/opds/shelf/<int:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_shelf(book_id): def feed_shelf(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
if current_user.is_anonymous: if current_user.is_anonymous:
@ -887,7 +925,7 @@ def feed_shelf(book_id):
@app.route("/opds/download/<book_id>/<book_format>/") @app.route("/opds/download/<book_id>/<book_format>/")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
@download_required @download_required
def get_opds_download_link(book_id, book_format): def get_opds_download_link(book_id, book_format):
book_format = book_format.split(".")[0] book_format = book_format.split(".")[0]
@ -911,7 +949,7 @@ def get_opds_download_link(book_id, book_format):
@app.route("/ajax/book/<string:uuid>") @app.route("/ajax/book/<string:uuid>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def get_metadata_calibre_companion(uuid): def get_metadata_calibre_companion(uuid):
entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first() entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
if entry is not None: if entry is not None:
@ -2157,7 +2195,7 @@ def serve_book(book_id, book_format):
@app.route("/opds/cover_240_240/<path:book_id>") @app.route("/opds/cover_240_240/<path:book_id>")
@app.route("/opds/cover_90_90/<path:book_id>") @app.route("/opds/cover_90_90/<path:book_id>")
@app.route("/opds/cover/<path:book_id>") @app.route("/opds/cover/<path:book_id>")
@requires_basic_auth_if_no_ano @basic_auth_required_check(config.config_use_ldap)
def feed_get_cover(book_id): def feed_get_cover(book_id):
book = db.session.query(db.Books).filter(db.Books.id == book_id).first() book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
return helper.get_book_cover(book.path) return helper.get_book_cover(book.path)
@ -2360,20 +2398,22 @@ def login():
return redirect(url_for('basic_configuration')) return redirect(url_for('basic_configuration'))
if current_user is not None and current_user.is_authenticated: if current_user is not None and current_user.is_authenticated:
return redirect(url_for('index')) return redirect(url_for('index'))
if config.config_use_ldap and not ldap_support:
flash(_(u"Cannot activate LDAP authentication"), category="error")
if request.method == "POST": if request.method == "POST":
form = request.form.to_dict() form = request.form.to_dict()
user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == form['username'].strip().lower()).first() user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == form['username'].strip().lower()).first()
if config.config_use_ldap and user: if ldap_support and config.config_use_ldap and user:
import ldap
try: try:
ub.User.try_login(form['username'], form['password']) if ldap.bind_user(form['username'], form['password']) is not None:
login_user(user, remember=True) login_user(user, remember=True)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success") flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
return redirect_back(url_for("index")) return redirect_back(url_for("index"))
except ldap.INVALID_CREDENTIALS: except LDAPException as exception:
ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr) app.logger.error( 'Login Error: ' + str(exception))
app.logger.info('LDAP Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress) ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
flash(_(u"Wrong Username or Password"), category="error") app.logger.info('LDAP Login failed for user "' + form['username'] + ', IP-address :' + ipAdress)
flash(_(u"Wrong Username or Password"), category="error")
elif user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest": elif user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest":
login_user(user, remember=True) login_user(user, remember=True)
flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success") flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
@ -3099,11 +3139,19 @@ def configuration_helper(origin):
if "config_ebookconverter" in to_save: if "config_ebookconverter" in to_save:
content.config_ebookconverter = int(to_save["config_ebookconverter"]) content.config_ebookconverter = int(to_save["config_ebookconverter"])
#LDAP configuratop, #LDAP configuration,
content.config_use_ldap = 0
if "config_use_ldap" in to_save and to_save["config_use_ldap"] == "on": if "config_use_ldap" in to_save and to_save["config_use_ldap"] == "on":
if not "config_ldap_provider_url" in to_save or not "config_ldap_dn" in to_save: if not to_save["config_ldap_provider_url"] or not to_save["config_ldap_port"] or not to_save["config_ldap_dn"] or not to_save["config_ldap_user_object"]:
ub.session.commit()
flash(_(u'Please enter a LDAP provider, port, DN and user object identifier'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"),
page="config")
elif not to_save["config_ldap_serv_username"] or not to_save["config_ldap_serv_password"]:
ub.session.commit() ub.session.commit()
flash(_(u'Please enter a LDAP provider and a DN'), category="error") flash(_(u'Please enter a LDAP service account and password'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin, return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError, gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"), goodreads=goodreads_support, title=_(u"Basic Configuration"),
@ -3111,8 +3159,36 @@ def configuration_helper(origin):
else: else:
content.config_use_ldap = 1 content.config_use_ldap = 1
content.config_ldap_provider_url = to_save["config_ldap_provider_url"] content.config_ldap_provider_url = to_save["config_ldap_provider_url"]
content.config_ldap_port = to_save["config_ldap_port"]
content.config_ldap_schema = to_save["config_ldap_schema"]
content.config_ldap_serv_username = to_save["config_ldap_serv_username"]
content.config_ldap_serv_password = base64.b64encode(to_save["config_ldap_serv_password"])
content.config_ldap_dn = to_save["config_ldap_dn"] content.config_ldap_dn = to_save["config_ldap_dn"]
db_change = True content.config_ldap_user_object = to_save["config_ldap_user_object"]
reboot_required = True
content.config_ldap_use_ssl = 0
content.config_ldap_use_tls = 0
content.config_ldap_require_cert = 0
content.config_ldap_openldap = 0
if "config_ldap_use_ssl" in to_save and to_save["config_ldap_use_ssl"] == "on":
content.config_ldap_use_ssl = 1
if "config_ldap_use_tls" in to_save and to_save["config_ldap_use_tls"] == "on":
content.config_ldap_use_tls = 1
if "config_ldap_require_cert" in to_save and to_save["config_ldap_require_cert"] == "on":
content.config_ldap_require_cert = 1
if "config_ldap_openldap" in to_save and to_save["config_ldap_openldap"] == "on":
content.config_ldap_openldap = 1
if "config_ldap_cert_path " in to_save:
if content.config_ldap_cert_path != to_save["config_ldap_cert_path "]:
if os.path.isfile(to_save["config_ldap_cert_path "]) or to_save["config_ldap_cert_path "] is u"":
content.config_certfile = to_save["config_ldap_cert_path "]
else:
ub.session.commit()
flash(_(u'Certfile location is not valid, please enter correct path'), category="error")
return render_title_template("config_edit.html", content=config, origin=origin,
gdrive=gdriveutils.gdrive_support, gdriveError=gdriveError,
goodreads=goodreads_support, title=_(u"Basic Configuration"),
page="config")
# Remote login configuration # Remote login configuration
content.config_remote_login = ("config_remote_login" in to_save and to_save["config_remote_login"] == "on") content.config_remote_login = ("config_remote_login" in to_save and to_save["config_remote_login"] == "on")

@ -1 +1,2 @@
python_ldap>=3.0.0 python_ldap>=3.0.0
flask-simpleldap
Loading…
Cancel
Save