mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-23 23:13:38 -06:00
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:
parent
10515431c7
commit
7c60fb3377
@ -65,6 +65,17 @@ LOG_FILE = 'pgadmin4.log'
|
|||||||
# Server settings
|
# 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
|
# The default port on which the app server will listen if not set in the
|
||||||
# environment by the runtime
|
# environment by the runtime
|
||||||
DEFAULT_SERVER_PORT = 5050
|
DEFAULT_SERVER_PORT = 5050
|
||||||
|
@ -20,6 +20,27 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
|||||||
import config
|
import config
|
||||||
from pgadmin import create_app
|
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
|
# Server starup
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
"""The main pgAdmin module. This handles the application initialisation tasks,
|
"""The main pgAdmin module. This handles the application initialisation tasks,
|
||||||
such as setup of logging, dynamic loading of modules etc."""
|
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.sqlalchemy import SQLAlchemy
|
||||||
from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required
|
from flask.ext.security import Security, SQLAlchemyUserDatastore, login_required
|
||||||
|
from flask_security.utils import login_user
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from settings_model import db, Role, User
|
from settings_model import db, Role, User
|
||||||
|
|
||||||
@ -66,6 +67,10 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + config.SQLITE_PATH.replace('\\', '/')
|
||||||
|
|
||||||
|
# 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_RECOVERABLE'] = True
|
||||||
app.config['SECURITY_CHANGEABLE'] = True
|
app.config['SECURITY_CHANGEABLE'] = True
|
||||||
|
|
||||||
@ -100,6 +105,29 @@ def create_app(app_name=config.APP_NAME):
|
|||||||
app.logger.info('Registering blueprint module: %s' % f)
|
app.logger.info('Registering blueprint module: %s' % f)
|
||||||
app.register_blueprint(module.views.blueprint)
|
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!
|
# All done!
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
app.logger.debug('URL map: %s' % app.url_map)
|
app.logger.debug('URL map: %s' % app.url_map)
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
@ -17,18 +17,23 @@
|
|||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">File <span class="caret"></span></a>
|
<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">
|
<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.test') }}">Test URL</a></li>
|
||||||
<li><a href="{{ url_for('utils.ping') }}">Ping</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 class="divider"></li>
|
||||||
<li><a href="{{ url_for('security.logout') }}">Logout</a></li>
|
<li><a href="{{ url_for('security.logout') }}">Logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
{% endif %}
|
||||||
<li><a href="#"><img src="{{ username | gravatar }}" width="18" height="18"> {{ username }}</a></li>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
28
web/setup.py
28
web/setup.py
@ -16,7 +16,7 @@ from flask.ext.security import Security, SQLAlchemyUserDatastore
|
|||||||
from flask.ext.security.utils import encrypt_password
|
from flask.ext.security.utils import encrypt_password
|
||||||
from settings_model import db, Role, User
|
from settings_model import db, Role, User
|
||||||
|
|
||||||
import getpass, os, sys
|
import getpass, os, random, sys, string
|
||||||
|
|
||||||
# Configuration settings
|
# Configuration settings
|
||||||
import config
|
import config
|
||||||
@ -31,8 +31,8 @@ print "======================================\n"
|
|||||||
|
|
||||||
local_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config_local.py')
|
local_config = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'config_local.py')
|
||||||
if not os.path.isfile(local_config):
|
if not os.path.isfile(local_config):
|
||||||
print "%s does not exist.\n" % local_config
|
print "The configuration file %s does not exist.\n" % local_config
|
||||||
print "Before running this script, ensure that config_local.py has been created"
|
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 "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 "at bare minimum. See config.py for more information and a complete list of"
|
||||||
print "settings. Exiting..."
|
print "settings. Exiting..."
|
||||||
@ -43,16 +43,24 @@ if os.path.isfile(config.SQLITE_PATH):
|
|||||||
print "The configuration database %s already exists and will not be overwritten.\nExiting..." % config.SQLITE_PATH
|
print "The configuration database %s already exists and will not be overwritten.\nExiting..." % config.SQLITE_PATH
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Prompt the user for their default username and password.
|
if config.SERVER_MODE == False:
|
||||||
print "Enter the email address and password to use for the initial pgAdmin user account:\n"
|
print "NOTE: Configuring authentication for DESKTOP mode."
|
||||||
email = ''
|
email = config.DESKTOP_USER
|
||||||
while email == '':
|
p1 = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)])
|
||||||
|
|
||||||
|
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: ")
|
email = raw_input("Email address: ")
|
||||||
|
|
||||||
pprompt = lambda: (getpass.getpass(), getpass.getpass('Retype password: '))
|
pprompt = lambda: (getpass.getpass(), getpass.getpass('Retype password: '))
|
||||||
|
|
||||||
p1, p2 = pprompt()
|
p1, p2 = pprompt()
|
||||||
while p1 != p2:
|
while p1 != p2:
|
||||||
print('Passwords do not match. Try again')
|
print('Passwords do not match. Try again')
|
||||||
p1, p2 = pprompt()
|
p1, p2 = pprompt()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user