Make rainloop use internal auth

master
Florent Daigniere 4 years ago
parent 6518ef19af
commit 906a051925

@ -7,7 +7,6 @@ import ipaddress
import socket
import tenacity
SUPPORTED_AUTH_METHODS = ["none", "plain"]
@ -49,11 +48,19 @@ def handle_authentication(headers):
user = models.User.query.get(user_email)
status = False
if user:
for token in user.tokens:
if (token.check_password(password) and
(not token.ip or token.ip == ip)):
status = True
if user.check_password(password):
# webmails
if len(password) == 64 and ip == app.config['WEBMAIL_ADDRESS']:
if user.verify_temp_token(password):
status = True
# All tokens are 32 characters hex lowercase
if len(password) == 32:
for token in user.tokens:
if (token.check_password(password) and
(not token.ip or token.ip == ip)):
status = True
break
if not status and user.check_password(password):
status = True
if status:
if protocol == "imap" and not user.enable_imap:

@ -43,6 +43,18 @@ def admin_authentication():
return ""
return flask.abort(403)
@internal.route("/auth/user")
def user_authentication():
""" Fails if the user is not authenticated.
"""
if (not flask_login.current_user.is_anonymous
and flask_login.current_user.enabled):
response = flask.Response()
response.headers["X-User"] = flask_login.current_user.get_id()
response.headers["X-User-Token"] = models.User.get_temp_token(flask_login.current_user.get_id())
return response
return flask.abort(403)
@internal.route("/auth/basic")
def basic_authentication():

@ -12,6 +12,7 @@ import re
import time
import os
import glob
import hmac
import smtplib
import idna
import dns
@ -425,6 +426,15 @@ class User(Base, Email):
user = cls.query.get(email)
return user if (user and user.enabled and user.check_password(password)) else None
@classmethod
def get_temp_token(cls, email):
user = cls.query.get(email)
return hmac.new(bytearray(app.secret_key,'utf-8'), bytearray("{}|{}".format(datetime.utcnow().strftime("%Y%m%d"), email), 'utf-8'), 'sha256').hexdigest() if (user and user.enabled) else None
def verify_temp_token(self, token):
return hmac.compare_digest(b''.fromhex(self.get_temp_token(self.email)), b''.fromhex(token))
class Alias(Base, Email):
""" An alias is an email address that redirects to some destination.

@ -47,6 +47,9 @@ def announcement():
flask.flash('Your announcement was sent', 'success')
return flask.render_template('announcement.html', form=form)
@ui.route('/webmail', methods=['GET'])
def webmail():
return flask.redirect(app.config['WEB_WEBMAIL'])
@ui.route('/client', methods=['GET'])
def client():

@ -133,7 +133,27 @@ http {
{% endif %}
include /etc/nginx/proxy.conf;
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
auth_request /internal/auth/user;
proxy_pass http://$webmail;
error_page 403 @webmail_login;
}
location {{ WEB_WEBMAIL }}/sso.php {
{% if WEB_WEBMAIL != '/' %}
rewrite ^({{ WEB_WEBMAIL }})$ $1/ permanent;
rewrite ^{{ WEB_WEBMAIL }}/(.*) /$1 break;
{% endif %}
include /etc/nginx/proxy.conf;
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
auth_request /internal/auth/user;
auth_request_set $user $upstream_http_x_user;
auth_request_set $token $upstream_http_x_user_token;
proxy_set_header X-Remote-User $user;
proxy_set_header X-Remote-User-Token $token;
proxy_pass http://$webmail;
error_page 403 @webmail_login;
}
location @webmail_login {
return 302 {{ WEB_ADMIN }}/ui/login?next=ui.webmail;
}
{% endif %}

@ -35,6 +35,7 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists
COPY include.php /var/www/html/include.php
COPY sso.php /var/www/html/sso.php
COPY php.ini /php.ini
COPY application.ini /application.ini

@ -7,6 +7,8 @@ attachment_size_limit = {{ MAX_FILESIZE }}
allow_admin_panel = Off
[labs]
custom_login_link='sso.php'
custom_logout_link='{{ WEB_ADMIN }}/ui/logout'
allow_gravatar = Off
[contacts]

@ -0,0 +1,31 @@
<?php
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
if (!defined('APP_VERSION')) {
$version = file_get_contents('/data/VERSION');
if ($version) {
define('APP_VERSION', $version);
define('APP_INDEX_ROOT_FILE', __FILE__);
define('APP_INDEX_ROOT_PATH', str_replace('\\', '/', rtrim(dirname(__FILE__), '\\/').'/'));
}
}
if (file_exists(APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php')) {
include APP_INDEX_ROOT_PATH.'rainloop/v/'.APP_VERSION.'/include.php';
} else {
echo '[105] Missing version directory';
exit(105);
}
// Retrieve email and password
if (in_array('HTTP_X_REMOTE_USER', $_SERVER) && in_array('HTTP_X_REMOTE_USER_TOKEN', $_SERVER)) {
$email = $_SERVER['HTTP_X_REMOTE_USER'];
$password = $_SERVER['HTTP_X_REMOTE_USER_TOKEN'];
$ssoHash = \RainLoop\Api::GetUserSsoHash($email, $password);
// redirect to webmail sso url
header('Location: index.php?sso&hash='.$ssoHash);
}
else {
header('HTTP/1.0 403 Forbidden');
}

@ -24,6 +24,7 @@ conf.jinja("/application.ini", os.environ, "/data/_data_/_default_/configs/appli
conf.jinja("/php.ini", os.environ, "/usr/local/etc/php/conf.d/rainloop.ini")
os.system("chown -R www-data:www-data /data")
os.system("chmod -R a+rX /var/www/html/")
os.execv("/usr/local/bin/apache2-foreground", ["apache2-foreground"])

Loading…
Cancel
Save