mirror of
https://github.com/YunoHost-Apps/calibreweb_ynh.git
synced 2024-09-03 18:16:20 +02:00
Merge pull request #15 from YunoHost-Apps/New-LDAP
LDAP and SSO integration
This commit is contained in:
commit
82fda027ec
8 changed files with 187 additions and 11 deletions
|
@ -41,6 +41,8 @@ or
|
||||||
chmod o+rw path/to/library
|
chmod o+rw path/to/library
|
||||||
```
|
```
|
||||||
* Do not use a Nextcloud folder. It's all right if the folder is an external storage in Nextcloud but not if it's an internal one : Changing the data in the library will cause trouble with the sync
|
* Do not use a Nextcloud folder. It's all right if the folder is an external storage in Nextcloud but not if it's an internal one : Changing the data in the library will cause trouble with the sync
|
||||||
|
* "Magic link feature is not yet available
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
* Report a bug: https://github.com/YunoHost-Apps/calibre_ynh/issues
|
* Report a bug: https://github.com/YunoHost-Apps/calibre_ynh/issues
|
||||||
|
@ -68,6 +70,8 @@ sudo yunohost app upgrade calibreweb -u https://github.com/Yunohost-Apps/calibre
|
||||||
- [ ] User and possibly LDAP integration
|
- [ ] User and possibly LDAP integration
|
||||||
- [X] Package_check integration
|
- [X] Package_check integration
|
||||||
- [X] On backup/remove/upgrade : check for database location to update settings
|
- [X] On backup/remove/upgrade : check for database location to update settings
|
||||||
|
- [ ] enable magic link
|
||||||
|
- [ ] Add cronjob to reload database
|
||||||
|
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#useless as long as V1.0 not issued
|
SOURCE_URL=https://github.com/janeczku/calibre-web/archive/c527d1f49a2213e523957fd90d814c075bacde89.zip
|
||||||
SOURCE_URL=https://github.com/janeczku/calibre-web/archive/d0fd1a46014006138977398ee65f48c98df937e7.zip
|
SOURCE_SUM=61aff733df259382ae53646e5445ac973a0c4fe70e54ec4d3ed63a7f66c4f04f
|
||||||
SOURCE_SUM=0d297719f32670840fb1fcee52d3e73fa6213127709809d9a232f862d037af03
|
|
||||||
SOURCE_FORMAT=zip
|
SOURCE_FORMAT=zip
|
||||||
|
|
|
@ -8,4 +8,7 @@ config_use_goodreads=0,
|
||||||
config_logfile=\'\',
|
config_logfile=\'\',
|
||||||
config_converterpath=\'\',
|
config_converterpath=\'\',
|
||||||
config_calibre=\'\',
|
config_calibre=\'\',
|
||||||
config_uploading=\'$upload\'
|
config_use_ldap=1,
|
||||||
|
config_ldap_provider_url=\'localhost:389\',
|
||||||
|
config_ldap_dn=\'uid=%s,ou=users,dc=yunohost,dc=org\',
|
||||||
|
config_uploading=\'$upload\'
|
||||||
|
|
|
@ -4,12 +4,13 @@ location __PATH__ {
|
||||||
if ($scheme = http) {
|
if ($scheme = http) {
|
||||||
rewrite ^ https://$server_name$request_uri? permanent;
|
rewrite ^ https://$server_name$request_uri? permanent;
|
||||||
}
|
}
|
||||||
proxy_pass http://localhost:__PORT__;
|
proxy_pass http://localhost:__PORT__;
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Scheme $scheme;
|
proxy_set_header X-Scheme $scheme;
|
||||||
proxy_set_header X-Script-Name __PATH__;
|
proxy_set_header X-Script-Name __PATH__;
|
||||||
|
proxy_set_header X-Remote-User $remote_user;
|
||||||
|
|
||||||
# Include SSOWAT user panel.
|
# Include SSOWAT user panel.
|
||||||
include conf.d/yunohost_panel.conf.inc;
|
include conf.d/yunohost_panel.conf.inc;
|
||||||
|
|
|
@ -92,7 +92,7 @@ pip install --target $final_path/vendor -r $final_path/requirements.txt
|
||||||
#=================================================
|
#=================================================
|
||||||
#Cannot use empty string for X-script-name, causes an issue in the python prg
|
#Cannot use empty string for X-script-name, causes an issue in the python prg
|
||||||
if [ $path_url = "/" ] ; then
|
if [ $path_url = "/" ] ; then
|
||||||
ynh_replace_string "X-Script-Name __PATH__;" "X-Script-Name /$app;" ../conf/nginx.conf
|
ynh_replace_string "X-Script-Name __PATH__;" "X-Script-Name $app;" ../conf/nginx.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a dedicated nginx config
|
# Create a dedicated nginx config
|
||||||
|
|
24
sources/patches/app-config.patch
Normal file
24
sources/patches/app-config.patch
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
--- a/cps/templates/config_edit.html 2019-01-12 09:01:08.000000000 +0100
|
||||||
|
+++ b/cps/templates/config_edit.html 2019-01-13 11:21:11.000000000 +0100
|
||||||
|
@@ -162,6 +162,21 @@
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
+ <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 %}>
|
||||||
|
+ <label for="config_use_ldap">{{_('Use')}} LDAP Authentication</label>
|
||||||
|
+ </div>
|
||||||
|
+ <div data-related="ldap-settings">
|
||||||
|
+ <div class="form-group">
|
||||||
|
+ <label for="config_ldap_provider_url">{{_('LDAP Provider URL')}}</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">
|
||||||
|
+ </div>
|
||||||
|
+ <div class="form-group">
|
||||||
|
+ <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">
|
||||||
|
+ </div>
|
||||||
|
+ </div>
|
||||||
|
+ </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
72
sources/patches/app-ub.patch
Normal file
72
sources/patches/app-ub.patch
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
--- a/cps/ub.py 2019-01-12 09:01:08.000000000 +0100
|
||||||
|
+++ b/cps/ub.py 2019-01-13 11:21:11.000000000 +0100
|
||||||
|
@@ -148,6 +148,14 @@
|
||||||
|
def __repr__(self):
|
||||||
|
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
|
||||||
|
# User Base (all access methods are declared there)
|
||||||
|
@@ -306,6 +314,9 @@
|
||||||
|
config_use_goodreads = Column(Boolean)
|
||||||
|
config_goodreads_api_key = Column(String)
|
||||||
|
config_goodreads_api_secret = Column(String)
|
||||||
|
+ config_use_ldap = Column(Boolean)
|
||||||
|
+ config_ldap_provider_url = Column(String)
|
||||||
|
+ config_ldap_dn = Column(String)
|
||||||
|
config_mature_content_tags = Column(String)
|
||||||
|
config_logfile = Column(String)
|
||||||
|
config_ebookconverter = Column(Integer, default=0)
|
||||||
|
@@ -379,6 +390,9 @@
|
||||||
|
self.config_use_goodreads = data.config_use_goodreads
|
||||||
|
self.config_goodreads_api_key = data.config_goodreads_api_key
|
||||||
|
self.config_goodreads_api_secret = data.config_goodreads_api_secret
|
||||||
|
+ self.config_use_ldap = data.config_use_ldap
|
||||||
|
+ self.config_ldap_provider_url = data.config_ldap_provider_url
|
||||||
|
+ self.config_ldap_dn = data.config_ldap_dn
|
||||||
|
if data.config_mature_content_tags:
|
||||||
|
self.config_mature_content_tags = data.config_mature_content_tags
|
||||||
|
else:
|
||||||
|
@@ -662,13 +676,20 @@
|
||||||
|
conn.execute("ALTER TABLE Settings ADD column `config_calibre` String DEFAULT ''")
|
||||||
|
session.commit()
|
||||||
|
try:
|
||||||
|
+ session.query(exists().where(Settings.config_use_ldap)).scalar()
|
||||||
|
+ except exc.OperationalError:
|
||||||
|
+ conn = engine.connect()
|
||||||
|
+ conn.execute("ALTER TABLE Settings ADD column `config_use_ldap` INTEGER DEFAULT 0")
|
||||||
|
+ conn.execute("ALTER TABLE Settings ADD column `config_ldap_provider_url` String DEFAULT ''")
|
||||||
|
+ conn.execute("ALTER TABLE Settings ADD column `config_ldap_dn` String DEFAULT ''")
|
||||||
|
+ session.commit()
|
||||||
|
+ try:
|
||||||
|
session.query(exists().where(Settings.config_theme)).scalar()
|
||||||
|
except exc.OperationalError: # Database is not compatible, some rows are missing
|
||||||
|
conn = engine.connect()
|
||||||
|
conn.execute("ALTER TABLE Settings ADD column `config_theme` INTEGER DEFAULT 0")
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
-
|
||||||
|
# Remove login capability of user Guest
|
||||||
|
conn = engine.connect()
|
||||||
|
conn.execute("UPDATE user SET password='' where nickname = 'Guest' and password !=''")
|
||||||
|
@@ -778,6 +799,12 @@
|
||||||
|
migrate_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
|
||||||
|
config = Config()
|
||||||
|
searched_ids = {}
|
73
sources/patches/app-web.patch
Normal file
73
sources/patches/app-web.patch
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
--- ./ori-calibre-web/cps/web.py 2019-01-12 09:01:08.000000000 +0100
|
||||||
|
+++ ./calibre-web-Yunohost_integration/cps/web.py 2019-01-13 20:11:57.000000000 +0100
|
||||||
|
@@ -58,6 +58,8 @@
|
||||||
|
import server
|
||||||
|
from reverseproxy import ReverseProxied
|
||||||
|
|
||||||
|
+vlogout = 0
|
||||||
|
+
|
||||||
|
try:
|
||||||
|
from googleapiclient.errors import HttpError
|
||||||
|
except ImportError:
|
||||||
|
@@ -2360,10 +2362,29 @@
|
||||||
|
return redirect(url_for('basic_configuration'))
|
||||||
|
if current_user is not None and current_user.is_authenticated:
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
+ auth_user = request.headers.get('X-Remote-User')
|
||||||
|
+ global vlogout
|
||||||
|
+ if auth_user and config.config_use_ldap and not vlogout:
|
||||||
|
+ vlogout = 0
|
||||||
|
+ user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == auth_user.strip().lower()).first()
|
||||||
|
+ login_user(user, remember=True)
|
||||||
|
+ flash(_(u"you are now logged in as: '%(nickname)s'", nickname=user.nickname), category="success")
|
||||||
|
+ return redirect(url_for("index"))
|
||||||
|
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":
|
||||||
|
+ if config.config_use_ldap and user:
|
||||||
|
+ import ldap
|
||||||
|
+ try:
|
||||||
|
+ 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)
|
||||||
|
+ flash(_(u"Wrong Username or Password"), category="error")
|
||||||
|
+ elif user and check_password_hash(user.password, form['password']) and user.nickname is not "Guest":
|
||||||
|
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"))
|
||||||
|
@@ -2384,6 +2405,8 @@
|
||||||
|
@login_required
|
||||||
|
def logout():
|
||||||
|
if current_user is not None and current_user.is_authenticated:
|
||||||
|
+ global vlogout
|
||||||
|
+ vlogout = 1
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
@@ -3088,6 +3111,21 @@
|
||||||
|
if "config_ebookconverter" in to_save:
|
||||||
|
content.config_ebookconverter = int(to_save["config_ebookconverter"])
|
||||||
|
|
||||||
|
+ #LDAP configuratop,
|
||||||
|
+ 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:
|
||||||
|
+ ub.session.commit()
|
||||||
|
+ flash(_(u'Please enter a LDAP provider and a DN'), 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")
|
||||||
|
+ else:
|
||||||
|
+ content.config_use_ldap = 1
|
||||||
|
+ content.config_ldap_provider_url = to_save["config_ldap_provider_url"]
|
||||||
|
+ content.config_ldap_dn = to_save["config_ldap_dn"]
|
||||||
|
+ db_change = True
|
||||||
|
+
|
||||||
|
# Remote login configuration
|
||||||
|
content.config_remote_login = ("config_remote_login" in to_save and to_save["config_remote_login"] == "on")
|
||||||
|
if not content.config_remote_login:
|
Loading…
Add table
Reference in a new issue