Support a desktop authentication mode.

This uses a single default user in the config database, which is
auto-logged into the app when SERVER_MODE = False. In this mode we
also hide/remove user-related functions in the UI.
This commit is contained in:
Dave Page 2015-01-26 15:20:28 +00:00
parent 10515431c7
commit 7c60fb3377
5 changed files with 93 additions and 20 deletions

View File

@ -65,6 +65,17 @@ LOG_FILE = 'pgadmin4.log'
# Server settings
##########################################################################
# The server mode determines whether or not we're running on a web server
# requiring user authentication, or desktop mode which uses an automatic
# default login.
#
# DO NOT DISABLE SERVER MODE IF RUNNING ON A WEBSERVER!!
SERVER_MODE = True
# User ID (email address) to use for the default user in desktop mode.
# The default should be fine here, as it's not exposed in the app.
DESKTOP_USER = 'pgadmin4@pgadmin.org'
# The default port on which the app server will listen if not set in the
# environment by the runtime
DEFAULT_SERVER_PORT = 5050

View File

@ -20,6 +20,27 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
import config
from pgadmin import create_app
##########################################################################
# Sanity checks
##########################################################################
# Check for local settings if running in server mode
if config.SERVER_MODE == True:
local_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config_local.py')
if not os.path.isfile(local_config):
print "The configuration file %s does not exist.\n" % local_config
print "Before running this application, ensure that config_local.py has been created"
print "and sets values for SECRET_KEY, SECURITY_PASSWORD_SALT and CSRF_SESSION_KEY"
print "at bare minimum. See config.py for more information and a complete list of"
print "settings. Exiting..."
sys.exit(1)
# Check if the database exists. If it does not, tell the user and exit.
if not os.path.isfile(config.SQLITE_PATH):
print "The configuration database %s does not exist.\n" % config.SQLITE_PATH
print "Please run 'python %s' to create it.\nExiting..." % os.path.join(os.path.dirname(os.path.realpath(__file__)), 'setup.py')
sys.exit(1)
##########################################################################
# Server starup
##########################################################################

View File

@ -10,9 +10,10 @@
"""The main pgAdmin module. This handles the application initialisation tasks,
such as setup of logging, dynamic loading of modules etc."""
from flask import Flask
from flask import Flask, abort
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required
from flask_security.utils import login_user
from flask_mail import Mail
from settings_model import db, Role, User
@ -66,8 +67,12 @@ def create_app(app_name=config.APP_NAME):
##########################################################################
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
app.config['SECURITY_RECOVERABLE'] = True
app.config['SECURITY_CHANGEABLE'] = True
# Only enable password related functionality in server mode.
if config.SERVER_MODE == True:
# TODO: Figure out how to disable /logout and /login
app.config['SECURITY_RECOVERABLE'] = True
app.config['SECURITY_CHANGEABLE'] = True
# Create database connection object and mailer
db.init_app(app)
@ -100,6 +105,29 @@ def create_app(app_name=config.APP_NAME):
app.logger.info('Registering blueprint module: %s' % f)
app.register_blueprint(module.views.blueprint)
##########################################################################
# Handle the desktop login
##########################################################################
@app.before_request
def before_request():
"""Login the default user if running in desktop mode"""
if config.SERVER_MODE == False:
user = user_datastore.get_user(config.DESKTOP_USER)
# Throw an error if we failed to find the desktop user, to give
# the sysadmin a hint. We'll continue to try to login anyway as
# that'll through a nice 500 error for us.
if user is None:
app.logger.error('The desktop user %s was not found in the configuration database.' % config.DESKTOP_USER)
abort(401)
login_user(user)
##########################################################################
# All done!
##########################################################################
app.logger.debug('URL map: %s' % app.url_map)
return app

View File

@ -17,18 +17,23 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">File <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="{{ url_for('security.change_password') }}">Change Password</a></li>
<li><a href="{{ url_for('utils.test') }}">Test URL</a></li>
<li><a href="{{ url_for('utils.ping') }}">Ping</a></li>
</ul>
</li>
</ul>
{% if config.SERVER_MODE %}
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><img src="{{ username | gravatar }}" width="18" height="18"> {{ username }} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ url_for('security.change_password') }}">Change Password</a></li>
<li class="divider"></li>
<li><a href="{{ url_for('security.logout') }}">Logout</a></li>
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#"><img src="{{ username | gravatar }}" width="18" height="18"> {{ username }}</a></li>
</li>
</ul>
{% endif %}
</div>
</div>

View File

@ -16,7 +16,7 @@ from flask.ext.security import Security, SQLAlchemyUserDatastore
from flask.ext.security.utils import encrypt_password
from settings_model import db, Role, User
import getpass, os, sys
import getpass, os, random, sys, string
# Configuration settings
import config
@ -31,8 +31,8 @@ print "======================================\n"
local_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config_local.py')
if not os.path.isfile(local_config):
print "%s does not exist.\n" % local_config
print "Before running this script, ensure that config_local.py has been created"
print "The configuration file %s does not exist.\n" % local_config
print "Before running this application, ensure that config_local.py has been created"
print "and sets values for SECRET_KEY, SECURITY_PASSWORD_SALT and CSRF_SESSION_KEY"
print "at bare minimum. See config.py for more information and a complete list of"
print "settings. Exiting..."
@ -43,18 +43,26 @@ if os.path.isfile(config.SQLITE_PATH):
print "The configuration database %s already exists and will not be overwritten.\nExiting..." % config.SQLITE_PATH
sys.exit(1)
# Prompt the user for their default username and password.
print "Enter the email address and password to use for the initial pgAdmin user account:\n"
email = ''
while email == '':
email = raw_input("Email address: ")
if config.SERVER_MODE == False:
print "NOTE: Configuring authentication for DESKTOP mode."
email = config.DESKTOP_USER
p1 = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)])
pprompt = lambda: (getpass.getpass(), getpass.getpass('Retype password: '))
else:
print "NOTE: Configuring authentication for SERVER mode.\n"
# Prompt the user for their default username and password.
print "Enter the email address and password to use for the initial pgAdmin user account:\n"
email = ''
while email == '':
email = raw_input("Email address: ")
pprompt = lambda: (getpass.getpass(), getpass.getpass('Retype password: '))
p1, p2 = pprompt()
while p1 != p2:
print('Passwords do not match. Try again')
p1, p2 = pprompt()
while p1 != p2:
print('Passwords do not match. Try again')
p1, p2 = pprompt()
# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)