216 lines
7.8 KiB
Plaintext
216 lines
7.8 KiB
Plaintext
import os
|
|
import lasso
|
|
|
|
from quixote import get_publisher, get_response, get_session, redirect, get_session_manager
|
|
from quixote.directory import Directory
|
|
from quixote.util import StaticDirectory
|
|
|
|
import admin
|
|
import backoffice
|
|
import liberty
|
|
from qommon import saml2
|
|
|
|
from qommon import errors
|
|
from qommon import logger
|
|
from qommon import get_cfg
|
|
from qommon import template
|
|
from qommon.form import *
|
|
import qommon.ident
|
|
|
|
from users import User
|
|
|
|
|
|
class IdentDirectory(Directory):
|
|
def _q_lookup(self, component):
|
|
get_response().breadcrumb.append(('ident/', None))
|
|
return qommon.ident.get_method_directory(component)
|
|
|
|
|
|
class LoginDirectory(Directory):
|
|
_q_exports = ['']
|
|
|
|
def _q_index [html] (self):
|
|
logger.info('login')
|
|
ident_methods = get_cfg('identification', {}).get('methods', [])
|
|
|
|
if len(ident_methods) == 0:
|
|
idps = get_cfg('idp', {})
|
|
if len(idps) == 0:
|
|
return template.error_page(_('Authentication subsystem is not yet configured.'))
|
|
ident_methods = ['idp'] # fallback to old behaviour; liberty.
|
|
|
|
if len(ident_methods) == 1:
|
|
method = ident_methods[0]
|
|
return qommon.ident.login(method)
|
|
else:
|
|
form = Form(enctype='multipart/form-data')
|
|
form.add(RadiobuttonsWidget, 'method',
|
|
options = [(x.key, _(x.description)) \
|
|
for x in qommon.ident.get_method_classes() if \
|
|
x.key in ident_methods],
|
|
delim = '<br/>')
|
|
form.add_submit('submit', _('Submit'))
|
|
|
|
if form.is_submitted() and not form.has_errors():
|
|
method = form.get_widget('method').parse()
|
|
if qommon.ident.base.ident_classes[method]().is_interactive():
|
|
return redirect('../ident/%s/login' % method)
|
|
else:
|
|
return qommon.ident.login(method)
|
|
else:
|
|
template.html_top(_('Login'))
|
|
'<p>%s</p>' % _('Select the identification method you want to use :')
|
|
form.render()
|
|
|
|
class RegisterDirectory(Directory):
|
|
_q_exports = ['']
|
|
|
|
def _q_index [html] (self):
|
|
logger.info('register')
|
|
ident_methods = get_cfg('identification', {}).get('methods', [])
|
|
|
|
if len(ident_methods) == 0:
|
|
idps = get_cfg('idp', {})
|
|
if len(idps) == 0:
|
|
return template.error_page(_('Authentication subsystem is not yet configured.'))
|
|
ident_methods = ['idp'] # fallback to old behaviour; liberty.
|
|
|
|
if len(ident_methods) == 1:
|
|
method = ident_methods[0]
|
|
return qommon.ident.register(method)
|
|
else:
|
|
pass # XXX: register page when there is more than one ident method
|
|
|
|
def _q_lookup(self, component):
|
|
return qommon.ident.get_method_directory(component)
|
|
|
|
|
|
class RootDirectory(Directory):
|
|
_q_exports = ['', 'admin', 'backoffice', 'login', 'logout', 'liberty', 'saml',
|
|
'ident', 'register']
|
|
|
|
def _q_index [html] (self):
|
|
template.html_top('Lasso Conformance SP')
|
|
|
|
if not get_request().user:
|
|
form = Form(enctype='multipart/form-data')
|
|
form.add(HtmlWidget, '<div id="sso-options">')
|
|
form.add(CheckboxWidget, 'force_authn', value = False,
|
|
title = _('Force Authentication (ForceAuthn)'))
|
|
form.add(CheckboxWidget, 'is_passive',
|
|
title = _('No interaction (IsPassive)'))
|
|
form.add(CheckboxWidget, 'allow_create', value = True,
|
|
title = _('Allow new federation'))
|
|
form.add(SingleSelectWidget, 'nid_format',
|
|
title = _('Name Identifier Format'),
|
|
options = [('persistent', _('Persistent')),
|
|
('transient', _('Transient')),
|
|
('none', _('(none'))])
|
|
# XXX: affiliation
|
|
form.add(SingleSelectWidget, 'consent',
|
|
title = _('Consent'),
|
|
options = ['(empty)', 'obtained', 'prior', 'current-implicit',
|
|
'current-explicit', 'unavailable', 'inapplicable'])
|
|
form.add(SingleSelectWidget, 'authn_context',
|
|
title = _('Authn Req Context'),
|
|
options = ['(empty)', 'password', 'password on protected transport',
|
|
'Client Certificate'])
|
|
form.add(SingleSelectWidget, 'matching',
|
|
title = _('Matching Rule'),
|
|
options = ['(empty)', 'exact', 'minimum', 'maximum', 'better'])
|
|
form.add(HtmlWidget, '</div>')
|
|
|
|
for kidp, idp in get_cfg('idp', {}).items():
|
|
form.add_submit(kidp, _('Log on %s') % kidp)
|
|
|
|
if form.is_submitted():
|
|
return self.do_login(form)
|
|
|
|
if get_request().user:
|
|
'<p>%s</p>' % _('Logged in (%s)') % get_request().user.display_name
|
|
'<p id="logout"><a href="logout">%s</a></p>' % _('Logout')
|
|
else:
|
|
form.render()
|
|
|
|
'<pre>'
|
|
get_session().lasso_identity_provider_id
|
|
'</pre>'
|
|
|
|
|
|
def do_login(self, form):
|
|
server = misc.get_lasso_server(protocol = 'saml2')
|
|
login = lasso.Login(server)
|
|
|
|
idp = None
|
|
# XXX: get idp from submitted button
|
|
|
|
login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT) # XXX: method must be an option
|
|
|
|
nid_format = form.get_widget('nid_format').parse()
|
|
if nid_format == 'persistent':
|
|
login.request.nameIDPolicy.format = lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
|
|
elif nid_format == 'transient':
|
|
login.request.nameIDPolicy.format = lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT
|
|
elif nid_format == 'none':
|
|
login.request.nameIDPolicy.format = lasso.SAML2_NAME_IDENTIFIER_FORMAT_NONE
|
|
|
|
login.request.nameIDPolicy.allowCreate = form.get_widget('allow_create').parse()
|
|
login.request.forceAuthn = form.get_widget('force_authn').parse()
|
|
login.request.isPassive = form.get_widget('is_passive').parse()
|
|
|
|
consent = form.get_widget('consent').parse()
|
|
if consent:
|
|
login.request.consent = 'urn:oasis:names:tc:SAML:2.0:consent:%s' % consent
|
|
|
|
login.buildAuthnRequestMsg()
|
|
return redirect(login.msgUrl)
|
|
|
|
|
|
def logout(self):
|
|
logger.info('logout')
|
|
session = get_session()
|
|
if not session:
|
|
return redirect('/')
|
|
ident_methods = get_cfg('identification', {}).get('methods', [])
|
|
if not 'idp' in ident_methods:
|
|
get_session_manager().expire_session()
|
|
return redirect('/')
|
|
|
|
provider = misc.get_provider(
|
|
misc.get_provider_key(get_session().lasso_identity_provider_id))
|
|
|
|
if provider.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0:
|
|
return self.saml.slo_sp()
|
|
else:
|
|
return self.liberty.singleLogout()
|
|
|
|
def _q_traverse(self, path):
|
|
session = get_session()
|
|
if session:
|
|
get_request().user = session.get_user()
|
|
else:
|
|
get_request().user = None
|
|
|
|
response = get_response()
|
|
response.filter = {}
|
|
if not hasattr(response, 'breadcrumb'):
|
|
response.breadcrumb = [ ('', _('Home')) ]
|
|
|
|
return Directory._q_traverse(self, path)
|
|
|
|
def _q_lookup(self, component):
|
|
if component == 'themes':
|
|
dirname = os.path.join(get_publisher().data_dir, 'themes')
|
|
return StaticDirectory(dirname, follow_symlinks = True)
|
|
|
|
raise errors.TraversalError()
|
|
|
|
admin = admin.RootDirectory()
|
|
backoffice = backoffice.RootDirectory()
|
|
saml = saml2.Saml2Directory()
|
|
liberty = liberty.LibertyDirectory()
|
|
login = LoginDirectory()
|
|
register = RegisterDirectory()
|
|
ident = IdentDirectory()
|
|
|