Docker-in-Docker (DinD) capabilities of public runners deactivated. More info

Commit ace424e5 authored by Marc Betoule's avatar Marc Betoule
Browse files

Various level of authentication

parent 22fd692f
......@@ -1035,15 +1035,49 @@ Pipeline(pipedot, codedir=, prefix=, env=MyEnvironment)
Pipeweb use the cherrypy web framework server and can be run behind an
apache webserver which brings essentially two advantages:
- https support.
- faster static files serving.
See the [[http://www.cherrypy.org/wiki/TableOfContents][cherrypy]] documentation for hints about this.
- access to *_mod apache facilities (https, gzip, authentication facilities ...).
- faster static files serving (the pipelet appli actually use quite few of them so the actual gain is marginal).
There is actually several way of doing so, the [[http://tools.cherrypy.org/wiki/BehindApache][cherrypy]] documentation
giving hints about each. We describe here an example case using
mod_rewrite and virtual hosting.
1. The first thing we need is a working installation of apache with
mod_rewrite activated. On a debian-like distribution this usually
obtain by:
=sudo a2enmod rewrite=
=sudo a2enmod proxy=
=sudo a2enmod proxy_http=
2. We then configure apache to rewrite request to the cherrypy apps
except for the static files of the application that will be served
directly. Here is a sample configuration file for a dedicated
virtual host named pipeweb with pipelet installed under
=/usr/local/lib/python2.6/dist-packages/=.
#+begin_src apache
<VirtualHost pipeweb:80>
ServerAdmin pipeweb_admin@localhost
DocumentRoot /usr/local/lib/python2.6/dist-packages/pipelet
# ErrorLog /some/custom/error_file.log
# CustomLog /some/custom/access_file.log common
RewriteEngine on
RewriteRule ^/static/(.*) /usr/local/lib/python2.6/dist-packages/pipelet/static/$1 [L]
RewriteRule ^(.*) http://127.0.0.1:8080$1 [proxy]
</VirtualHost>
#+end_src
3. Restart apache and start the pipeweb application to serve on the
specified address and port:
=pipeweb start -H 127.0.0.1=
When deploying the pipeweb interface in a production environment, one may want
* The Pipelet actors
This section document the code for developers.
The code documentation can be built using the doxygen configuration
file
This section document the code for developers. The code documentation
can be built using the doxygen configuration file
pipelet/doc/pipelet.dox
......
# Form based authentication for CherryPy. Requires the
# Session tool to be loaded.
#
""" Simple authentication for pipeweb.
"""
import cherrypy
import sqlite3
def read_access(func):
""" Decorator to set read only access to a web page (cherrypy web function)
Parameters
----------
func: web function
def check_access(auth_type, access_level):
""" Check whether user has sufficient access rights.
Depending on the configuration passed through auth_type:
- grant access without verification
- check the access level of an otherwise authenticated user
- perform Basic http authentication and check access rights
- perform Digest http authentication and check access rights
Parameters:
-----------
auth_type: either 'None', 'ACL', 'Basic', 'Digest'
access_level: the required access level.
"""
return cherrypy.tools.digest_auth(realm="pipeweb",users=lambda: get_credentials(1))(func)
cherrypy.log.error('auth_type:%s'%auth_type)
realm = "pipeweb"
if auth_type == 'None':
#No autorization check required
return True
def write_access(func):
""" Decorator to set read only accessto a web page (cherrypy web function)
if not 'authorization' in cherrypy.request.headers:
return False
ah = cherrypy.lib.httpauth.parseAuthorization(cherrypy.request.headers['authorization'])
if ah is None:
raise cherrypy.HTTPError(400, 'Bad Request')
Parameters
----------
func: web function
"""
return cherrypy.tools.digest_auth(realm="pipeweb",users=lambda: get_credentials(2))(func)
dic = get_credentials(access_level)
if auth_type == 'ACL':
#Check that otherwise authenticated user has the required
#access level
if ah['username'] in dic.keys():
return True
else:
return False
password = dic.get(ah["username"], None)
encrypt = lambda x:x
cherrypy.log.error('password:%s'%password)
if cherrypy.lib.httpauth.checkResponse(ah, password, method=cherrypy.request.method,
encrypt=encrypt, realm=realm):
cherrypy.request.login = ah["username"]
return True
cherrypy.request.login = False
return False
def get_credentials(access_level=1):
""" Get users/passwd from pipe data base.
......@@ -49,6 +78,36 @@ def get_credentials(access_level=1):
conn.close()
return dic
def ask_auth(auth_type):
realm = "pipeweb"
if auth_type == "Basic":
cherrypy.response.headers['www-authenticate'] = cherrypy.lib.httpauth.basicAuth(realm)
elif auth_type == "Digest":
cherrypy.response.headers['www-authenticate'] = cherrypy.lib.httpauth.digestAuth(realm)
def read_access(auth_type="Digest"):
""" Require read only access on a web page
"""
if check_access (auth_type, 1):
return
ask_auth(auth_type)
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
def write_access(auth_type="Digest"):
""" Require write accessto a web page
"""
if check_access (auth_type, 2):
return
ask_auth(auth_type)
raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
# Making this module a custom cherrypy toolbox
pipeauth = cherrypy._cptools.Toolbox('pipeauth')
pipeauth.read_access = cherrypy.Tool('on_start_resource', read_access)
pipeauth.write_access = cherrypy.Tool('on_start_resource', write_access)
def acl_setup(db_file):
""" Set user/passwd table in pipe database.
......
......@@ -23,7 +23,8 @@ current_dir = os.path.dirname(os.path.abspath(__file__))
from glob import glob
import shutil
from cherrypy.lib.static import serve_file
from auth import read_access, write_access
#from auth import read_access, write_access
import auth
import re
import pickle
......@@ -103,7 +104,7 @@ class Web:
return list(set(lst))
@cherrypy.expose
@write_access
@auth.pipeauth.write_access()
def addtag (self, segid, tag):
""" Add new tag to the database
......@@ -147,7 +148,7 @@ class Web:
r = pickle.dump(d,f)
@cherrypy.expose
@write_access
@auth.pipeauth.write_access()
def deltag (self, tag):
""" Delete tag from the database
......@@ -196,7 +197,7 @@ class Web:
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def filter (self, tag=None, date=None):
""" Print the pipeline instances matching tag and date.
......@@ -229,7 +230,7 @@ class Web:
return html
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def index(self, highlight=None, thumbnail=None):
""" Pipeline instances tree view
......@@ -239,7 +240,6 @@ class Web:
----------
highlight: list of segid (optional), filter the printed seg by segid.
"""
conn = sqlite3.connect(self.db_file,check_same_thread=True)
conn.text_factory=str
# get all instances
......@@ -356,7 +356,7 @@ class Web:
return html
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def product(self, segid=None, status=None):
""" Products index.
......@@ -468,7 +468,7 @@ class Web:
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def code(self, segid=None):
""" Segment's files index.
......@@ -559,7 +559,7 @@ class Web:
@cherrypy.expose
@write_access
@auth.pipeauth.write_access()
def del_lst_seg(self, seglist):
""" Delete a pipeline instance.
......@@ -586,7 +586,7 @@ class Web:
@cherrypy.expose
@write_access
@auth.pipeauth.write_access()
def del_lst_prod(self, segid, taskid):
""" Delete recursively a list of products.
......@@ -611,7 +611,7 @@ class Web:
raise cherrypy.HTTPRedirect('/'+self.name+'/',303)
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def pipedir(self, segid=None, directory=None):
""" Print the content of a directory.
......@@ -660,7 +660,7 @@ class Web:
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def log(self, logdir):
""" Print the content of the log directory.
"""
......@@ -674,14 +674,14 @@ class Web:
return html
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def serve_log(self, filename):
""" Print the content of the log file.
"""
return serve_file(filename, content_type='text/plain', disposition="inline")
@cherrypy.expose
@write_access
@auth.pipeauth.write_access()
def delete_log(self, logdir):
""" Delete the content of the log directory.
"""
......@@ -706,7 +706,7 @@ class Web:
return filepath
@cherrypy.expose
@read_access
@auth.pipeauth.read_access()
def download(self, segid=None, filepath=None):
""" Download a file.
......@@ -880,6 +880,9 @@ def main():
parser.add_option('-a', '--access-file',
help='Logging file for access when run in daemon mode',
default=os.path.expanduser('~/pipelet.access'))
parser.add_option('-A', '--authentication-type',
help='What kind of authentication is performed by cherrypy, can be one of ["Digest", "Basic", "ACL", "None"]',
default="Digest")
parser.add_option('-i', '--pid-file',
help='Store the pid in daemon mode',
default=os.path.expanduser('~/pipelet.pid'))
......@@ -895,21 +898,29 @@ def main():
'log.screen':False,
'log.error_file': options.error_file,
'log.access_file':options.access_file,
'server.pidfile':options.pid_file}
'server.pidfile':options.pid_file,
'pipeauth.read_access.auth_type':options.authentication_type,
'pipeauth.write_access.auth_type':options.authentication_type}
}
if options.no_daemon:
config['global']['log.screen'] = True
cherrypy.config.update(config)
cherrypy.config.update(options.config_file)
cherrypy.tree.mount(PipeIndex(),"",config)
app = cherrypy.tree.mount(PipeIndex(),"",config)
if hasattr(app, 'toolboxes'):
# CherryPy 3.1+
app.toolboxes['pipeauth'] = auth.pipeauth
cherrypy.engine.start()
cherrypy.engine.block()
exit(0)
if options.krenew:
cherrypy.config.update(config)
cherrypy.config.update(options.config_file)
cherrypy.tree.mount(PipeIndex(),"",config)
app = cherrypy.tree.mount(PipeIndex(),"",config)
if hasattr(app, 'toolboxes'):
# CherryPy 3.1+
app.toolboxes['pipeauth'] = auth.pipeauth
cherrypy.engine.start()
cherrypy.engine.block()
exit(0)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment