From f40fc5aa75d5f1bd874cd671617fd00fba21ad05 Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sun, 16 Jun 2019 08:59:25 +0200 Subject: [PATCH] Update LDAP --- cps/admin.py | 10 ++--- cps/ldap.py | 7 +++- cps/opds.py | 67 ++++++++++++++++++---------------- cps/templates/config_edit.html | 53 ++++++++++++++------------- cps/ub.py | 12 +++--- cps/web.py | 28 ++++++++------ 6 files changed, 96 insertions(+), 81 deletions(-) diff --git a/cps/admin.py b/cps/admin.py index 3712420a..f6fd838f 100644 --- a/cps/admin.py +++ b/cps/admin.py @@ -26,8 +26,6 @@ import os import json import time from datetime import datetime, timedelta -# import uuid -import random try: from imp import reload except ImportError: @@ -42,7 +40,7 @@ from sqlalchemy import and_ from sqlalchemy.exc import IntegrityError from werkzeug.security import generate_password_hash -from . import constants, logger +from . import constants, logger, ldap from . import db, ub, Server, get_locale, config, updater_thread, babel, gdriveutils from .helper import speaking_language, check_valid_domain, check_unrar, send_test_mail, generate_random_password, \ send_registration_mail @@ -50,6 +48,8 @@ from .gdriveutils import is_gdrive_ready, gdrive_support, downloadFile, deleteDa from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano feature_support = dict() +feature_support['ldap'] = ldap.ldap_supported() + try: from goodreads.client import GoodreadsClient feature_support['goodreads'] = True @@ -62,11 +62,11 @@ except ImportError: # except ImportError: # feature_support['rar'] = False -try: +'''try: import ldap feature_support['ldap'] = True except ImportError: - feature_support['ldap'] = False + feature_support['ldap'] = False''' try: from oauth_bb import oauth_check diff --git a/cps/ldap.py b/cps/ldap.py index 43a8fcba..0688475a 100644 --- a/cps/ldap.py +++ b/cps/ldap.py @@ -31,6 +31,7 @@ log = logger.create() class Ldap(): def __init__(self): + self.ldap = None return def init_app(self, app): @@ -55,7 +56,11 @@ class Ldap(): # app.config['LDAP_BASE_DN'] = 'ou=users,dc=yunohost,dc=org' # app.config['LDAP_USER_OBJECT_FILTER'] = '(uid=%s)' - # ldap = LDAP(app) + self.ldap = LDAP(app) elif config.config_login_type == 1 and not ldap_support: log.error('Cannot activate ldap support, did you run \'pip install --target vendor -r optional-requirements.txt\'?') + + @classmethod + def ldap_supported(cls): + return ldap_support diff --git a/cps/opds.py b/cps/opds.py index d72d1163..2ba95635 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -31,24 +31,23 @@ from flask_login import current_user from sqlalchemy.sql.expression import func, text, or_, and_ from werkzeug.security import check_password_hash -from . import logger, config, db, ub +from . import logger, config, db, ub, ldap from .helper import fill_indexpage, get_download_link, get_book_cover from .pagination import Pagination from .web import common_filters, get_search_results, render_read_books, download_required -try: - import ldap - ldap_support = True -except ImportError: - ldap_support = False opds = Blueprint('opds', __name__) + log = logger.create() +ldap_support = ldap.ldap_supported() def requires_basic_auth_if_no_ano(f): @wraps(f) def decorated(*args, **kwargs): + if config.config_login_type == 1 and ldap_support: + return ldap.ldap.basic_auth_required(*args, **kwargs) auth = request.authorization if config.config_anonbrowse != 1: if not auth or not check_auth(auth.username, auth.password): @@ -57,39 +56,43 @@ def requires_basic_auth_if_no_ano(f): return decorated -def basic_auth_required_check(condition): + +'''def basic_auth_required_check(condition): + print("susi") def decorator(f): if condition and ldap_support: - return ldap.basic_auth_required(f) + return ldap.ldap.basic_auth_required(f) return requires_basic_auth_if_no_ano(f) - return decorator + return decorator''' + @opds.route("/opds/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_index(): return render_xml_template('index.xml') @opds.route("/opds/osd") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_osd(): return render_xml_template('osd.xml', lang='en-EN') + @opds.route("/opds/search", defaults={'query': ""}) @opds.route("/opds/search/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_cc_search(query): return feed_search(query.strip()) @opds.route("/opds/search", methods=["GET"]) -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_normal_search(): return feed_search(request.args.get("query").strip()) @opds.route("/opds/new") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_new(): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -98,7 +101,7 @@ def feed_new(): @opds.route("/opds/discover") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_discover(): entries = db.session.query(db.Books).filter(common_filters()).order_by(func.random())\ .limit(config.config_books_per_page) @@ -107,7 +110,7 @@ def feed_discover(): @opds.route("/opds/rated") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_best_rated(): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -116,7 +119,7 @@ def feed_best_rated(): @opds.route("/opds/hot") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_hot(): off = request.args.get("offset") or 0 all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id)).order_by( @@ -141,7 +144,7 @@ def feed_hot(): @opds.route("/opds/author") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_authorindex(): off = request.args.get("offset") or 0 entries = db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(common_filters())\ @@ -152,7 +155,7 @@ def feed_authorindex(): @opds.route("/opds/author/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_author(book_id): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -161,7 +164,7 @@ def feed_author(book_id): @opds.route("/opds/publisher") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_publisherindex(): off = request.args.get("offset") or 0 entries = db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\ @@ -172,7 +175,7 @@ def feed_publisherindex(): @opds.route("/opds/publisher/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_publisher(book_id): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -182,7 +185,7 @@ def feed_publisher(book_id): @opds.route("/opds/category") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_categoryindex(): off = request.args.get("offset") or 0 entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\ @@ -193,7 +196,7 @@ def feed_categoryindex(): @opds.route("/opds/category/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_category(book_id): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -202,7 +205,7 @@ def feed_category(book_id): @opds.route("/opds/series") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_seriesindex(): off = request.args.get("offset") or 0 entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\ @@ -213,7 +216,7 @@ def feed_seriesindex(): @opds.route("/opds/series/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_series(book_id): off = request.args.get("offset") or 0 entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), @@ -223,7 +226,7 @@ def feed_series(book_id): @opds.route("/opds/shelfindex/", defaults={'public': 0}) @opds.route("/opds/shelfindex/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_shelfindex(public): off = request.args.get("offset") or 0 if public is not 0: @@ -238,7 +241,7 @@ def feed_shelfindex(public): @opds.route("/opds/shelf/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_shelf(book_id): off = request.args.get("offset") or 0 if current_user.is_anonymous: @@ -262,14 +265,14 @@ def feed_shelf(book_id): @opds.route("/opds/download///") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano @download_required def opds_download_link(book_id, book_format): return get_download_link(book_id,book_format) @opds.route("/ajax/book/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def get_metadata_calibre_companion(uuid): entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first() if entry is not None: @@ -318,19 +321,19 @@ def render_xml_template(*args, **kwargs): @opds.route("/opds/cover_240_240/") @opds.route("/opds/cover_90_90/") @opds.route("/opds/cover/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_get_cover(book_id): return get_book_cover(book_id) @opds.route("/opds/readbooks/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_read_books(): off = request.args.get("offset") or 0 return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True) @opds.route("/opds/unreadbooks/") -@basic_auth_required_check(config.config_login_type) +@requires_basic_auth_if_no_ano def feed_unread_books(): off = request.args.get("offset") or 0 return render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True) diff --git a/cps/templates/config_edit.html b/cps/templates/config_edit.html index 353bdc5c..59800b98 100644 --- a/cps/templates/config_edit.html +++ b/cps/templates/config_edit.html @@ -186,67 +186,68 @@ {% endif %} {% if feature_support['ldap'] or feature_support['oauth'] %}
- - + + +
{% if feature_support['ldap'] %}
- +
- +
- +
- +
- +
- - + +
- - + +
- - + +
- +
- +
- +
- +
diff --git a/cps/ub.py b/cps/ub.py index faf344e1..70d97a20 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -40,10 +40,10 @@ from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.ext.declarative import declarative_base from werkzeug.security import generate_password_hash -try: +'''try: import ldap except ImportError: - pass + pass''' from . import constants, logger, cli @@ -172,12 +172,12 @@ class UserBase: return '' % self.nickname # Login via LDAP method - @staticmethod + '''@staticmethod def try_login(username, password,config_dn, ldap_provider_url): conn = get_ldap_connection(ldap_provider_url) conn.simple_bind_s( config_dn.replace("%s", username), - password) + password)''' # 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) @@ -795,10 +795,10 @@ def clean_database(): session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).delete() -#get LDAP connection +'''#get LDAP connection def get_ldap_connection(ldap_provider_url): conn = ldap.initialize('ldap://{}'.format(ldap_provider_url)) - return conn + return conn''' diff --git a/cps/web.py b/cps/web.py index c5074436..3f8964d4 100644 --- a/cps/web.py +++ b/cps/web.py @@ -41,7 +41,7 @@ from werkzeug.exceptions import default_exceptions from werkzeug.datastructures import Headers from werkzeug.security import generate_password_hash, check_password_hash -from . import constants, logger, isoLanguages +from . import constants, logger, isoLanguages, ldap from . import global_WorkerThread, searched_ids, lm, babel, db, ub, config, get_locale, app, language_table from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download from .helper import common_filters, get_search_results, fill_indexpage, speaking_language, check_valid_domain, \ @@ -52,6 +52,8 @@ from .pagination import Pagination from .redirect import redirect_back feature_support = dict() +feature_support['ldap'] = ldap.ldap_supported() + try: from .oauth_bb import oauth_check, register_user_with_oauth, logout_oauth_user, get_oauth_status feature_support['oauth'] = True @@ -59,12 +61,6 @@ except ImportError: feature_support['oauth'] = False oauth_check = {} -try: - import ldap - feature_support['ldap'] = True -except ImportError: - feature_support['ldap'] = False - try: from goodreads.client import GoodreadsClient feature_support['goodreads'] = True @@ -221,6 +217,7 @@ def edit_required(f): return inner + # ################################### Helper functions ################################################################ @@ -244,6 +241,8 @@ def before_request(): # ################################### data provider functions ######################################################### + + @web.route("/ajax/emailstat") @login_required def get_email_status_json(): @@ -308,6 +307,7 @@ def toggle_read(book_id): log.error(u"Custom Column No.%d is not exisiting in calibre database", config.config_read_column) return "" + ''' @web.route("/ajax/getcomic///") @login_required @@ -359,6 +359,7 @@ def get_comic_book(book_id, book_format, page): return "", 204 ''' + # ################################### Typeahead ################################################################## @@ -434,6 +435,7 @@ def get_matching_tags(): # ################################### View Books list ################################################################## + @web.route("/", defaults={'page': 1}) @web.route('/page/') @login_required_if_no_ano @@ -757,6 +759,7 @@ def category_list(): # ################################### Task functions ################################################################ + @web.route("/tasks") @login_required def get_tasks_status(): @@ -768,6 +771,7 @@ def get_tasks_status(): # ################################### Search functions ################################################################ + @web.route("/search", methods=["GET"]) @login_required_if_no_ano def search(): @@ -963,6 +967,7 @@ def render_read_books(page, are_read, as_xml=False, order=None): # ################################### Download/Send ################################################################## + @web.route("/cover/") @login_required_if_no_ano def get_cover(book_id): @@ -1021,6 +1026,7 @@ def send_to_kindle(book_id, book_format, convert): # ################################### Login Logout ################################################################## + @web.route('/register', methods=['GET', 'POST']) def register(): if not config.config_public_reg: @@ -1087,17 +1093,17 @@ def login(): .first() if config.config_login_type == 1 and user and feature_support['ldap']: try: - if ldap.bind_user(form['username'], form['password']) is not None: + if ldap.ldap.bind_user(form['username'], form['password']) is not None: login_user(user, remember=True) flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success") return redirect_back(url_for("web.index")) - except ldap.INVALID_CREDENTIALS as e: + except ldap.ldap.INVALID_CREDENTIALS as e: log.error('Login Error: ' + str(e)) ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr) log.info('LDAP Login failed for user "%s" IP-adress: %s', form['username'], ipAdress) flash(_(u"Wrong Username or Password"), category="error") - except ldap.SERVER_DOWN: + except ldap.ldap.SERVER_DOWN: log.info('LDAP Login failed, LDAP Server down') flash(_(u"Could not login. LDAP server down, please contact your administrator"), category="error") '''except LDAPException as exception: @@ -1213,6 +1219,7 @@ def token_verified(): # ################################### Users own configuration ######################################################### + @web.route("/me", methods=["GET", "POST"]) @login_required def profile(): @@ -1279,7 +1286,6 @@ def profile(): page="me", registered_oauth=oauth_check, oauth_status=oauth_status) - # ###################################Show single book ##################################################################