allow creating users from reverse proxy headers

allowing login via reverse proxy auth is convenient, but it's not
convenient to have to create the users in advance. this PR allows users
to be optionally created if they don't already exist. we provide this as
an option in the UI
pull/2899/head
Igor Serebryany 8 months ago
parent 6a14e2cf68
commit b3adf67b49
No known key found for this signature in database
GPG Key ID: 0AF607692FD9EB24

@ -1793,6 +1793,8 @@ def _configuration_update_helper():
# Reverse proxy login configuration
_config_checkbox(to_save, "config_allow_reverse_proxy_header_login")
_config_string(to_save, "config_reverse_proxy_login_header_name")
_config_checkbox(to_save, "config_reverse_proxy_create_users")
_config_string(to_save, "config_reverse_proxy_email_header_name")
# OAuth configuration
if config.config_login_type == constants.LOGIN_OAUTH:

@ -79,7 +79,7 @@ class _Settings(_Base):
config_random_books = Column(Integer, default=4)
config_authors_max = Column(Integer, default=0)
config_read_column = Column(Integer, default=0)
config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines|Le|La|Les|L\'|Un|Une)\s+')
config_title_regex = Column(String, default=r'^(A|The|An|Der|Die|Das|Den|Ein|Eine|Einen|Dem|Des|Einem|Eines|Le|La|Les|L\'|Un|Une)\s+')
config_theme = Column(Integer, default=0)
config_log_level = Column(SmallInteger, default=logger.DEFAULT_LOG_LEVEL)
@ -147,6 +147,8 @@ class _Settings(_Base):
config_reverse_proxy_login_header_name = Column(String)
config_allow_reverse_proxy_header_login = Column(Boolean, default=False)
config_reverse_proxy_create_users = Column(Boolean, default=False)
config_reverse_proxy_email_header_name = Column(String)
schedule_start_time = Column(Integer, default=4)
schedule_duration = Column(Integer, default=10)

@ -154,6 +154,14 @@
<div class="col-xs-6 col-sm-7">{{_('Reverse Proxy Header Name')}}</div>
<div class="col-xs-6 col-sm-5">{{ config.config_reverse_proxy_login_header_name }}</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-7">{{_('Create Reverse Proxy Users')}}</div>
<div class="col-xs-6 col-sm-5">{{ display_bool_setting(config.config_reverse_proxy_create_users) }}</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-7">{{_('Reverse Proxy Email Header Name')}}</div>
<div class="col-xs-6 col-sm-5">{{ config.config_reverse_proxy_email_header_name }}</div>
</div>
{% endif %}
</div>
<a class="btn btn-default" id="db_config" href="{{url_for('admin.db_configuration')}}">{{_('Edit Calibre Database Configuration')}}</a>

@ -173,6 +173,14 @@
<label for="config_reverse_proxy_login_header_name">{{_('Reverse Proxy Header Name')}}</label>
<input type="text" class="form-control" id="config_reverse_proxy_login_header_name" name="config_reverse_proxy_login_header_name" value="{% if config.config_reverse_proxy_login_header_name != None %}{{ config.config_reverse_proxy_login_header_name }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<input type="checkbox" id="config_reverse_proxy_create_users" name="config_reverse_proxy_create_users" {% if config.config_reverse_proxy_create_users %}checked{% endif %}>
<label for="config_reverse_proxy_create_users">{{_('Create Reverse Proxy Users')}}</label>
</div>
<div class="form-group">
<label for="config_reverse_proxy_email_header_name">{{_('Reverse Proxy Email Header Name')}}</label>
<input type="text" class="form-control" id="config_reverse_proxy_email_header_name" name="config_reverse_proxy_email_header_name" value="{% if config.config_reverse_proxy_email_header_name != None %}{{ config.config_reverse_proxy_email_header_name }}{% endif %}" autocomplete="off">
</div>
</div>
{% if not config.config_is_initial %}
{% if feature_support['ldap'] or feature_support['oauth'] %}

@ -25,6 +25,8 @@ from flask import request, Response
from . import lm, ub, config, constants, services, logger, limiter
from .helper import generate_random_password, generate_password_hash, check_email
log = logger.create()
def login_required_if_no_ano(func):
@ -103,9 +105,51 @@ def load_user_from_reverse_proxy_header(req):
rp_header_username = req.headers.get(rp_header_name)
if rp_header_username:
user = _fetch_user_by_name(rp_header_username)
if not user and config.config_reverse_proxy_create_users:
create_user_from_reverse_proxy_header(req)
user = _fetch_user_by_name(rp_header_username)
if user:
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
login_user(user)
return user
return None
def create_user_from_reverse_proxy_header(req):
rp_header_name = config.config_reverse_proxy_login_header_name
username = req.headers.get(rp_header_name)
# does the user have an email address in the headers?
rp_email_header_name = config.config_reverse_proxy_email_header_name
if rp_email_header_name:
try:
email = check_email(req.headers.get(rp_email_header_name))
except Exception:
log.debug('No email address found in Reverse Proxy headers')
email = username + '@localhost'
# generate a random password
password = generate_random_password(config.config_password_min_length)
pwhash = generate_password_hash(password)
user = ub.User()
user.name = username
user.password = pwhash
user.email = email
user.default_language = config.config_default_language
user.locale = config.config_default_locale
user.role = config.config_default_role
user.sidebar_view = config.config_default_show
user.allowed_tags = config.config_allowed_tags
user.denied_tags = config.config_denied_tags
user.allowed_column_value = config.config_allowed_column_value
user.denied_column_value = config.config_denied_column_value
# save the user
ub.session.add(user)
try:
ub.session.commit()
except Exception as ex:
log.warning("Failed to create Reverse Proxy user: %s - %s", username, ex)
ub.session.rollback()

@ -1639,6 +1639,14 @@ msgstr ""
msgid "Reverse Proxy Header Name"
msgstr ""
#: cps/templates/admin.html:158 cps/templates/config_edit.html:178
msgid "Create Reverse Proxy Users"
msgstr ""
#: cps/templates/admin.html:162 cps/templates/config_edit.html:181
msgid "Reverse Proxy Email Header Name"
msgstr ""
#: cps/templates/admin.html:159
msgid "Edit Calibre Database Configuration"
msgstr ""

Loading…
Cancel
Save