diff --git a/cps/web.py b/cps/web.py
index 0937fdb7..a85bcf31 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -119,7 +119,7 @@ EXTENSIONS_CONVERT = {'pdf', 'epub', 'mobi', 'azw3', 'docx', 'rtf', 'fb2', 'lit'
# EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + (['rar','cbr'] if rar_support else []))
-oauth_check = []
+oauth_check = {}
'''class ReverseProxied(object):
"""Wrap the application in this middleware and configure the
@@ -2751,6 +2751,7 @@ def profile():
downloads = list()
languages = speaking_language()
translations = babel.list_translations() + [LC('en')]
+ oauth_status = get_oauth_status()
for book in content.downloads:
downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
if downloadBook:
@@ -2812,11 +2813,11 @@ def profile():
ub.session.rollback()
flash(_(u"Found an existing account for this e-mail address."), category="error")
return render_title_template("user_edit.html", content=content, downloads=downloads,
- title=_(u"%(name)s's profile", name=current_user.nickname))
+ title=_(u"%(name)s's profile", name=current_user.nickname, registered_oauth=oauth_check, oauth_status=oauth_status))
flash(_(u"Profile updated"), category="success")
return render_title_template("user_edit.html", translations=translations, profile=1, languages=languages,
content=content, downloads=downloads, title=_(u"%(name)s's profile",
- name=current_user.nickname), page="me")
+ name=current_user.nickname), page="me", registered_oauth=oauth_check, oauth_status=oauth_status)
@app.route("/admin/view")
@@ -3945,22 +3946,22 @@ def convert_bookformat(book_id):
return redirect(request.environ["HTTP_REFERER"])
-def register_oauth_blueprint(blueprint):
+def register_oauth_blueprint(blueprint, show_name):
if blueprint.name != "":
- oauth_check.append(blueprint.name)
+ oauth_check[blueprint.name] = show_name
def register_user_with_oauth(user=None):
- all_oauth = []
- for oauth in oauth_check:
+ all_oauth = {}
+ for oauth in oauth_check.keys():
if oauth + '_oauth_user_id' in session and session[oauth + '_oauth_user_id'] != '':
- all_oauth.append(oauth)
- if len(all_oauth) == 0:
+ all_oauth[oauth] = oauth_check[oauth]
+ if len(all_oauth.keys()) == 0:
return
if user is None:
- flash(_(u"Register with %s" % ", ".join(all_oauth)), category="success")
+ flash(_(u"Register with %s" % ", ".join(list(all_oauth.values()))), category="success")
else:
- for oauth in all_oauth:
+ for oauth in all_oauth.keys():
# Find this OAuth token in the database, or create it
query = ub.session.query(ub.OAuth).filter_by(
provider=oauth,
@@ -3980,7 +3981,7 @@ def register_user_with_oauth(user=None):
def logout_oauth_user():
- for oauth in oauth_check:
+ for oauth in oauth_check.keys():
if oauth + '_oauth_user_id' in session:
session.pop(oauth + '_oauth_user_id')
@@ -4006,20 +4007,22 @@ app.register_blueprint(github_blueprint, url_prefix='/login')
github_blueprint.backend = OAuthBackend(ub.OAuth, ub.session, user=current_user, user_required=True)
google_blueprint.backend = OAuthBackend(ub.OAuth, ub.session, user=current_user, user_required=True)
-register_oauth_blueprint(github_blueprint)
-register_oauth_blueprint(google_blueprint)
+
+if config.config_use_github_oauth:
+ register_oauth_blueprint(github_blueprint, 'GitHub')
+if config.config_use_google_oauth:
+ register_oauth_blueprint(google_blueprint, 'Google')
@oauth_authorized.connect_via(github_blueprint)
def github_logged_in(blueprint, token):
if not token:
- flash("Failed to log in with GitHub.", category="error")
+ flash(_("Failed to log in with GitHub."), category="error")
return False
resp = blueprint.session.get("/user")
if not resp.ok:
- msg = "Failed to fetch user info from GitHub."
- flash(msg, category="error")
+ flash(_("Failed to fetch user info from GitHub."), category="error")
return False
github_info = resp.json()
@@ -4030,13 +4033,12 @@ def github_logged_in(blueprint, token):
@oauth_authorized.connect_via(google_blueprint)
def google_logged_in(blueprint, token):
if not token:
- flash("Failed to log in with Google.", category="error")
+ flash(_("Failed to log in with Google."), category="error")
return False
resp = blueprint.session.get("/oauth2/v2/userinfo")
if not resp.ok:
- msg = "Failed to fetch user info from Google."
- flash(msg, category="error")
+ flash(_("Failed to fetch user info from Google."), category="error")
return False
google_info = resp.json()
@@ -4088,7 +4090,7 @@ def bind_oauth_or_register(provider, provider_user_id, redirect_url):
return redirect(url_for('index'))
else:
# bind to current user
- if current_user and not current_user.is_anonymous:
+ if current_user and current_user.is_authenticated:
oauth.user = current_user
try:
ub.session.add(oauth)
@@ -4101,6 +4103,46 @@ def bind_oauth_or_register(provider, provider_user_id, redirect_url):
return redirect(url_for(redirect_url))
+def get_oauth_status():
+ status = []
+ query = ub.session.query(ub.OAuth).filter_by(
+ user_id=current_user.id,
+ )
+ try:
+ oauths = query.all()
+ for oauth in oauths:
+ status.append(oauth.provider)
+ return status
+ except NoResultFound:
+ return None
+
+
+def unlink_oauth(provider):
+ if request.host_url + 'me' != request.referrer:
+ pass
+ query = ub.session.query(ub.OAuth).filter_by(
+ provider=provider,
+ user_id=current_user.id,
+ )
+ try:
+ oauth = query.one()
+ if current_user and current_user.is_authenticated:
+ oauth.user = current_user
+ try:
+ ub.session.delete(oauth)
+ ub.session.commit()
+ logout_oauth_user()
+ flash(_("Unlink to %(oauth)s success.", oauth=oauth_check[provider]), category="success")
+ except Exception as e:
+ app.logger.exception(e)
+ ub.session.rollback()
+ flash(_("Unlink to %(oauth)s failed.", oauth=oauth_check[provider]), category="error")
+ except NoResultFound:
+ app.logger.warning("oauth %s for user %d not fount" % (provider, current_user.id))
+ flash(_("Not linked to %(oauth)s.", oauth=oauth_check[provider]), category="error")
+ return redirect(url_for('profile'))
+
+
# notify on OAuth provider error
@oauth_error.connect_via(github_blueprint)
def github_error(blueprint, error, error_description=None, error_uri=None):
@@ -4129,6 +4171,12 @@ def github_login():
return redirect(url_for('login'))
+@app.route('/unlink/github', methods=["GET"])
+@login_required
+def github_login_unlink():
+ return unlink_oauth(github_blueprint.name)
+
+
@app.route('/google')
@google_oauth_required
def google_login():
@@ -4154,3 +4202,9 @@ def google_error(blueprint, error, error_description=None, error_uri=None):
uri=error_uri,
)
flash(msg, category="error")
+
+
+@app.route('/unlink/google', methods=["GET"])
+@login_required
+def google_login_unlink():
+ return unlink_oauth(google_blueprint.name)
From 30954cc27f3206fa62142c4881effafe77e7236c Mon Sep 17 00:00:00 2001
From: Krakinou
Date: Thu, 10 Jan 2019 23:51:01 +0100
Subject: [PATCH 06/96] Initial LDAP support
---
cps/ub.py | 15 +++++++++++++++
cps/web.py | 12 +++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/cps/ub.py b/cps/ub.py
index 57dbde6e..14cf0b24 100644
--- a/cps/ub.py
+++ b/cps/ub.py
@@ -14,6 +14,7 @@ import json
import datetime
from binascii import hexlify
import cli
+import ldap
engine = create_engine('sqlite:///{0}'.format(cli.settingspath), echo=False)
Base = declarative_base()
@@ -46,6 +47,8 @@ SIDEBAR_PUBLISHER = 4096
DEFAULT_PASS = "admin123"
DEFAULT_PORT = int(os.environ.get("CALIBRE_PORT", 8083))
+LDAP_PROVIDER_URL = 'ldap://localhost:389/'
+LDAP_PROTOCOL_VERSION = 3
class UserBase:
@@ -152,6 +155,13 @@ class UserBase:
def __repr__(self):
return '' % self.nickname
+ @staticmethod
+ def try_login(username, password):
+ conn = get_ldap_connection()
+ conn.simple_bind_s(
+ 'uid={},ou=users,dc=yunohost,dc=org'.format(username),
+ 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)
@@ -778,6 +788,11 @@ else:
migrate_Database()
clean_database()
+#get LDAP connection
+def get_ldap_connection():
+ conn = ldap.initialize(LDAP_PROVIDER_URL)
+ return conn
+
# Generate global Settings Object accessible from every file
config = Config()
searched_ids = {}
diff --git a/cps/web.py b/cps/web.py
index da240211..c78ae132 100644
--- a/cps/web.py
+++ b/cps/web.py
@@ -57,6 +57,7 @@ from redirect import redirect_back
import time
import server
from reverseproxy import ReverseProxied
+import ldap
try:
from googleapiclient.errors import HttpError
@@ -2342,7 +2343,16 @@ def login():
if request.method == "POST":
form = request.form.to_dict()
user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == form['username'].strip().lower()).first()
- if user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest":
+ try:
+ app.logger.info("Tryong LDAP connexion")
+ ub.User.try_login(form['username'], form['password'])
+ 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("index"))
+ except ldap.INVALID_CREDENTIALS:
+ ipAdress = request.headers.get('X-Forwarded-For', request.remote_addr)
+ app.logger.info('LDAP Login failed for user "' + form['username'] + '" IP-adress: ' + ipAdress)
+ if user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest" and not user.is_authenticated:
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("index"))
From 8d284b151d79daa892656a20c668953409659f85 Mon Sep 17 00:00:00 2001
From: Krakinou
Date: Sat, 12 Jan 2019 12:52:27 +0100
Subject: [PATCH 07/96] Edit html config
---
cps/templates/config_edit.html | 15 +++++++++++++++
cps/ub.py | 15 ++++++++++++++-
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/cps/templates/config_edit.html b/cps/templates/config_edit.html
index b2826b39..c12d3a9f 100644
--- a/cps/templates/config_edit.html
+++ b/cps/templates/config_edit.html
@@ -162,6 +162,21 @@
{% endif %}
+