Merge branch 'saml2_sp'
Integrate saml2 into Mandaye and merge branche 'sam2_sp'
|
@ -23,8 +23,7 @@ from mandaye.response import _500, _302, _401
|
|||
from mandaye.response import template_response
|
||||
from mandaye.server import get_response
|
||||
|
||||
from mandaye.config.backend import ManagerIDPUser, ManagerSPUser,\
|
||||
ManagerServiceProvider
|
||||
from mandaye.config import backend
|
||||
|
||||
try:
|
||||
from Crypto.Cipher import AES
|
||||
|
@ -192,16 +191,16 @@ a password_field key if you want to encode a password.")
|
|||
sp_login = post_values[self.form_values['username_field']]
|
||||
if config.encrypt_sp_password:
|
||||
self._encrypt_pwd(post_values)
|
||||
service_provider = ManagerServiceProvider.get_or_create(self.site_name)
|
||||
idp_user = ManagerIDPUser.get_or_create(unique_id)
|
||||
sp_user = ManagerSPUser.get_or_create(sp_login, post_values,
|
||||
service_provider = backend.ManagerServiceProvider.get_or_create(self.site_name)
|
||||
idp_user = backend.ManagerIDPUser.get_or_create(unique_id)
|
||||
sp_user = backend.ManagerSPUser.get_or_create(sp_login, post_values,
|
||||
idp_user, service_provider)
|
||||
sp_user.login = sp_login
|
||||
sp_user.post_values = post_values
|
||||
sp_user.idp_user = idp_user
|
||||
sp_user.last_connection = datetime.now()
|
||||
sp_user.service_provider = service_provider
|
||||
ManagerSPUser.save()
|
||||
backend.ManagerSPUser.save()
|
||||
env['beaker.session']['unique_id'] = unique_id
|
||||
env['beaker.session'][self.site_name] = sp_user.id
|
||||
env['beaker.session'].save()
|
||||
|
@ -251,7 +250,7 @@ a password_field key if you want to encode a password.")
|
|||
response = self.replay(env, post_values)
|
||||
if condition and eval(condition):
|
||||
sp_user.last_connection = datetime.now()
|
||||
ManagerSPUser.save()
|
||||
backend.ManagerSPUser.save()
|
||||
env['beaker.session'][self.site_name] = sp_user.id
|
||||
env['beaker.session'].save()
|
||||
return response
|
||||
|
@ -261,9 +260,9 @@ a password_field key if you want to encode a password.")
|
|||
def login(self, env, values, condition, request, response):
|
||||
""" Automatic login on a site with a form
|
||||
"""
|
||||
logger.debug('Trying to login on Mandaye')
|
||||
# Specific method to get current idp unique id
|
||||
unique_id = self.get_current_unique_id(env)
|
||||
logger.debug('Trying to login on Mandaye')
|
||||
if not unique_id:
|
||||
return _401('Access denied: invalid token')
|
||||
|
||||
|
@ -276,9 +275,9 @@ a password_field key if you want to encode a password.")
|
|||
|
||||
logger.debug('User %s successfully login' % env['beaker.session']['unique_id'])
|
||||
|
||||
idp_user = ManagerIDPUser.get(unique_id)
|
||||
service_provider = ManagerServiceProvider.get(self.site_name)
|
||||
sp_user = ManagerSPUser.get_last_connected(idp_user, service_provider)
|
||||
idp_user = backend.ManagerIDPUser.get(unique_id)
|
||||
service_provider = backend.ManagerServiceProvider.get(self.site_name)
|
||||
sp_user = backend.ManagerSPUser.get_last_connected(idp_user, service_provider)
|
||||
if not sp_user:
|
||||
logger.debug('User %s is not associate' % env['beaker.session']['unique_id'])
|
||||
return _302(values.get('associate_url') + "?type=first")
|
||||
|
@ -303,9 +302,9 @@ a password_field key if you want to encode a password.")
|
|||
if not login or not qs.has_key('id'):
|
||||
return _401('Access denied: beaker session invalid or not qs id')
|
||||
id = qs['id'][0]
|
||||
service_provider = ManagerServiceProvider.get(self.site_name)
|
||||
idp_user = ManagerServiceProvider.get(unique_id)
|
||||
sp_user = ManagerSPUser.get_last_connected(idp_user, service_provider)
|
||||
service_provider = backend.ManagerServiceProvider.get(self.site_name)
|
||||
idp_user = backend.ManagerServiceProvider.get(unique_id)
|
||||
sp_user = backend.ManagerSPUser.get_last_connected(idp_user, service_provider)
|
||||
if not sp_user:
|
||||
return _302(values.get('associate_url'))
|
||||
return self._login_sp_user(sp_user, env, 'response.code==302', values)
|
||||
|
@ -324,9 +323,9 @@ a password_field key if you want to encode a password.")
|
|||
if not login or not qs.has_key('id'):
|
||||
return _401('Access denied: beaker session invalid or not id')
|
||||
id = qs['id'][0]
|
||||
sp_user = ManagerSPUser.get_by_id(id)
|
||||
sp_user = backend.ManagerSPUser.get_by_id(id)
|
||||
if sp_user:
|
||||
ManagerSPUser.delete(sp_user)
|
||||
backend.ManagerSPUser.delete(sp_user)
|
||||
if qs.has_key('logout'):
|
||||
self.logout(env, values, request, response)
|
||||
return _302(values.get('next_url'))
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
import datetime
|
||||
import os
|
||||
import urllib2
|
||||
|
||||
import lasso
|
||||
|
||||
from authentic2.saml import saml2utils
|
||||
from urlparse import parse_qs
|
||||
|
||||
from mandaye import config, utils
|
||||
from mandaye.auth.authform import AuthForm
|
||||
from mandaye.response import _302, _500
|
||||
from mandaye.log import logger
|
||||
from mandaye.template import serve_template
|
||||
from mandaye.http import HTTPResponse, HTTPHeader
|
||||
|
||||
|
||||
class SAML2Auth(AuthForm):
|
||||
""" SAML 2 authentification
|
||||
"""
|
||||
|
||||
def __init__(self, form_values, site_name, saml2_config):
|
||||
""" saml2_config: saml 2 config module
|
||||
"""
|
||||
self.config = saml2_config
|
||||
self.metadata_map = (
|
||||
('AssertionConsumerService',
|
||||
lasso.SAML2_METADATA_BINDING_POST ,
|
||||
self.config.END_POINTS_PATH['single_sign_on_post']
|
||||
),
|
||||
)
|
||||
self.metadata_options = { 'key': self.config.SAML_SIGNATURE_PUBLIC_KEY }
|
||||
super(SAML2Auth, self).__init__(form_values, site_name)
|
||||
|
||||
def get_current_unique_id(self, env):
|
||||
return env['beaker.session']['unique_id']
|
||||
|
||||
def _get_idp_metadata_file_path(self):
|
||||
metadata_file_path = None
|
||||
if self.config.IDP_METADATA:
|
||||
metadata_file_path = os.path.join(config.data_dir,
|
||||
self.config.IDP_METADATA.\
|
||||
replace('://', '_').\
|
||||
replace('/', '_')
|
||||
)
|
||||
if not os.path.isfile(metadata_file_path):
|
||||
try:
|
||||
response = urllib2.urlopen(self.config.IDP_METADATA)
|
||||
metadata = response.read()
|
||||
except:
|
||||
return _500('sso', 'Unable to find metadata.')
|
||||
metadata_file = open(metadata_file_path, 'a+')
|
||||
metadata_file.write(metadata)
|
||||
metadata.close()
|
||||
return metadata_file_path
|
||||
|
||||
def _get_metadata(self, env):
|
||||
url_prefix = env['mandaye.scheme'] + '://' + env['HTTP_HOST']
|
||||
metadata_path = self.config.END_POINTS_PATH['metadata']
|
||||
single_sign_on_post_path = \
|
||||
self.config.END_POINTS_PATH['single_sign_on_post']
|
||||
metagen = saml2utils.Saml2Metadata(url_prefix + metadata_path,
|
||||
url_prefix = url_prefix)
|
||||
metagen.add_sp_descriptor(self.metadata_map, self.metadata_options)
|
||||
return str(metagen)
|
||||
|
||||
def sso(self, env, values, request, response):
|
||||
target_idp = None
|
||||
metadata_file_path = self._get_idp_metadata_file_path()
|
||||
if not metadata_file_path:
|
||||
return _500('sso', 'Unable to load provider.')
|
||||
logger.debug('sso: target_idp is %s' % target_idp)
|
||||
logger.debug('sso: metadata url is %s' % self.config.IDP_METADATA)
|
||||
logger.debug('sso: mandaye metadata are %s' % self._get_metadata(env))
|
||||
server = lasso.Server.newFromBuffers(self._get_metadata(env),
|
||||
self.config.SAML_SIGNATURE_PRIVATE_KEY)
|
||||
if not server:
|
||||
return _500('sso', 'Error creating server object.')
|
||||
logger.debug('sso: mandaye server object created')
|
||||
server.addProvider(lasso.PROVIDER_ROLE_IDP, metadata_file_path)
|
||||
login = lasso.Login(server)
|
||||
if not login:
|
||||
return _500('sso', 'Error creating login object.')
|
||||
http_method = self.config.AUTHNREQ_HTTP_METHOD
|
||||
try:
|
||||
login.initAuthnRequest(target_idp, http_method)
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error initiating request.', error)
|
||||
login.request.nameIDPolicy.format = self.config.SAML2_NAME_IDENTIFIER_FORMAT
|
||||
login.request.nameIDPolicy.allowCreate = self.config.ALLOW_CREATE
|
||||
login.request.nameIDPolicy.spNameQualifier = self.config.SP_NAME_QUALIFIER
|
||||
login.request.protocolBinding = self.config.AUTHNRESP_BINDING
|
||||
try:
|
||||
login.buildAuthnRequestMsg()
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error initiating request.', error)
|
||||
logger.debug('sso: set request id in session %s' % login.request.iD)
|
||||
env['beaker.session']['request_id'] = login.request.iD
|
||||
env['beaker.session'].save()
|
||||
|
||||
if not login.msgUrl:
|
||||
return _500('sso', 'Enable to perform sso by redirection.')
|
||||
return _302(login.msgUrl)
|
||||
|
||||
def single_sign_on_post(self, env, values, request, response):
|
||||
target_idp = None
|
||||
metadata_file_path = self._get_idp_metadata_file_path()
|
||||
if not metadata_file_path:
|
||||
return _500('single_sign_on_post', 'Unable to load provider.')
|
||||
server = lasso.Server.newFromBuffers(self._get_metadata(env),
|
||||
self.config.SAML_SIGNATURE_PRIVATE_KEY)
|
||||
if not server:
|
||||
return _500('singleSignOnPost', 'Error creating server object.')
|
||||
server.addProvider(lasso.PROVIDER_ROLE_IDP, metadata_file_path)
|
||||
login = lasso.Login(server)
|
||||
if not login:
|
||||
return _500('singleSignOnPost', 'Error creating login object.')
|
||||
|
||||
if env['REQUEST_METHOD'] != 'POST':
|
||||
return _500('singleSignOnPost', 'Not a POST request.')
|
||||
|
||||
msg = env['wsgi.input']
|
||||
params = parse_qs(msg.read())
|
||||
if not params or not lasso.SAML2_FIELD_RESPONSE in params.keys():
|
||||
return _500('singleSignOnPost', 'Missing response.')
|
||||
message = params[lasso.SAML2_FIELD_RESPONSE][0]
|
||||
logger.debug('sso: message posted %s' % message)
|
||||
|
||||
try:
|
||||
login.processAuthnResponseMsg(message)
|
||||
except:
|
||||
return _500('singleSignOnPost', 'Unable to proces authnresponse message.')
|
||||
|
||||
subject_confirmation = utils.get_absolute_uri(env)
|
||||
saml_request_id = env['beaker.session']['request_id']
|
||||
check = saml2utils.authnresponse_checking(login, subject_confirmation,
|
||||
logger, saml_request_id=saml_request_id)
|
||||
if not check:
|
||||
return _500('singleSignOnPost', 'error checking authn response %s' % env)
|
||||
logger.debug('sso: response successfully checked')
|
||||
|
||||
try:
|
||||
login.acceptSso()
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error validating sso.', error)
|
||||
logger.debug('sso: sso accepted, session validation')
|
||||
|
||||
env['beaker.session']['validated'] = True
|
||||
attributes = saml2utils.get_attributes_from_assertion(login.assertion,
|
||||
logger)
|
||||
env['beaker.session']['attributes'] = attributes
|
||||
env['beaker.session']['unique_id'] = login.nameIdentifier.content
|
||||
env['beaker.session'].save()
|
||||
|
||||
return _302('/')
|
||||
|
||||
|
||||
def metadata(self, env, values, request, response):
|
||||
title='metadata'
|
||||
headers = HTTPHeader({'Content-Type': ['text/xml']})
|
||||
return HTTPResponse(200, 'Found', headers,
|
||||
self._get_metadata(env))
|
||||
|
|
@ -5,7 +5,7 @@ from mandaye.exceptions import ImproperlyConfigured
|
|||
# rfc 1738 http://rfc.net/rfc1738.html
|
||||
db_url = 'sqlite:///test.db'
|
||||
|
||||
# Default local backend
|
||||
# Default backend
|
||||
import mandaye.backends.sql
|
||||
backend = mandaye.backends.sql
|
||||
|
||||
|
@ -15,7 +15,7 @@ keyfile = ''
|
|||
certfile = ''
|
||||
|
||||
# Log configuration
|
||||
debug = False
|
||||
debug = True
|
||||
syslog = False
|
||||
log_file = '/var/log/mandaye/mandaye.log'
|
||||
log_level = logging.INFO
|
||||
|
@ -33,6 +33,8 @@ template_directory = 'mandaye/templates'
|
|||
# Static folder
|
||||
static_root = 'mandaye/static'
|
||||
|
||||
# Data dir
|
||||
data_dir = '/var/tmp'
|
||||
|
||||
# Email notification configuration
|
||||
email_notification = False
|
||||
|
@ -55,10 +57,11 @@ encrypt_sp_password = False
|
|||
encrypt_secret = ''
|
||||
|
||||
hosts = {
|
||||
'localhost:8000': [
|
||||
'proxy.roleid.lan:8088': [
|
||||
{'path': r'/',
|
||||
'target': 'http://perdu.com',
|
||||
'mapping': None
|
||||
'mapping': None,
|
||||
'local': 'test'
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -86,10 +89,10 @@ hosts = {
|
|||
|
||||
# beaker session
|
||||
session_opts = {
|
||||
'session.type': 'file',
|
||||
'session.cookie_expires': True,
|
||||
'session.timeout': 3600,
|
||||
'session.data_dir': '/var/tmp/beaker',
|
||||
'session.type': 'file',
|
||||
'session.cookie_expires': True,
|
||||
'session.timeout': 3600,
|
||||
'session.data_dir': '/var/tmp/beaker'
|
||||
}
|
||||
|
||||
# token timeout
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
import lasso
|
||||
|
||||
# END_POINTS
|
||||
END_POINTS_PATH = {
|
||||
'metadata': '/mandaye/metadata',
|
||||
'single_sign_on_post': '/mandaye/singleSignOnPost'
|
||||
}
|
||||
|
||||
# Now only support for a single IdP
|
||||
IDP_METADATA = ("http://www.identity-hub.net/idp/saml2/metadata")
|
||||
|
||||
# SAML2 SP options
|
||||
AUTHNREQ_HTTP_METHOD = lasso.HTTP_METHOD_REDIRECT
|
||||
|
||||
# Only persistent make sense
|
||||
SAML2_NAME_IDENTIFIER_FORMAT = lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT
|
||||
ALLOW_CREATE = True
|
||||
SP_NAME_QUALIFIER = None
|
||||
|
||||
# Only POST is supported for now
|
||||
AUTHNRESP_BINDING = lasso.SAML2_METADATA_BINDING_POST
|
||||
|
||||
# FIXME: change this keys
|
||||
SAML_SIGNATURE_PUBLIC_KEY = '''-----BEGIN CERTIFICATE-----
|
||||
MIIDIzCCAgugAwIBAgIJANUBoick1pDpMA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV
|
||||
BAoTCkVudHJvdXZlcnQwHhcNMTAxMjE0MTUzMzAyWhcNMTEwMTEzMTUzMzAyWjAV
|
||||
MRMwEQYDVQQKEwpFbnRyb3V2ZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAvxFkfPdndlGgQPDZgFGXbrNAc/79PULZBuNdWFHDD9P5hNhZn9Kqm4Cp
|
||||
06Pe/A6u+g5wLnYvbZQcFCgfQAEzziJtb3J55OOlB7iMEI/T2AX2WzrUH8QT8NGh
|
||||
ABONKU2Gg4XiyeXNhH5R7zdHlUwcWq3ZwNbtbY0TVc+n665EbrfV/59xihSqsoFr
|
||||
kmBLH0CoepUXtAzA7WDYn8AzusIuMx3n8844pJwgxhTB7Gjuboptlz9Hri8JRdXi
|
||||
VT9OS9Wt69ubcNoM6zuKASmtm48UuGnhj8v6XwvbjKZrL9kA+xf8ziazZfvvw/VG
|
||||
Tm+IVFYB7d1x457jY5zjjXJvNysoowIDAQABo3YwdDAdBgNVHQ4EFgQUeF8ePnu0
|
||||
fcAK50iBQDgAhHkOu8kwRQYDVR0jBD4wPIAUeF8ePnu0fcAK50iBQDgAhHkOu8mh
|
||||
GaQXMBUxEzARBgNVBAoTCkVudHJvdXZlcnSCCQDVAaInJNaQ6TAMBgNVHRMEBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAy8l3GhUtpPHx0FxzbRHVaaUSgMwYKGPhE
|
||||
IdGhqekKUJIx8et4xpEMFBl5XQjBNq/mp5vO3SPb2h2PVSks7xWnG3cvEkqJSOeo
|
||||
fEEhkqnM45b2MH1S5uxp4i8UilPG6kmQiXU2rEUBdRk9xnRWos7epVivTSIv1Ncp
|
||||
lG6l41SXp6YgIb2ToT+rOKdIGIQuGDlzeR88fDxWEU0vEujZv/v1PE1YOV0xKjTT
|
||||
JumlBc6IViKhJeo1wiBBrVRIIkKKevHKQzteK8pWm9CYWculxT26TZ4VWzGbo06j
|
||||
o2zbumirrLLqnt1gmBDvDvlOwC/zAAyL4chbz66eQHTiIYZZvYgy
|
||||
-----END CERTIFICATE-----'''
|
||||
|
||||
SAML_SIGNATURE_PRIVATE_KEY = '''-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAvxFkfPdndlGgQPDZgFGXbrNAc/79PULZBuNdWFHDD9P5hNhZ
|
||||
n9Kqm4Cp06Pe/A6u+g5wLnYvbZQcFCgfQAEzziJtb3J55OOlB7iMEI/T2AX2WzrU
|
||||
H8QT8NGhABONKU2Gg4XiyeXNhH5R7zdHlUwcWq3ZwNbtbY0TVc+n665EbrfV/59x
|
||||
ihSqsoFrkmBLH0CoepUXtAzA7WDYn8AzusIuMx3n8844pJwgxhTB7Gjuboptlz9H
|
||||
ri8JRdXiVT9OS9Wt69ubcNoM6zuKASmtm48UuGnhj8v6XwvbjKZrL9kA+xf8ziaz
|
||||
Zfvvw/VGTm+IVFYB7d1x457jY5zjjXJvNysoowIDAQABAoIBAQCj8t2iKXya10HG
|
||||
V6Saaeih8aftoLBV38VwFqqjPU0+iKqDpk2JSXBhjI6s7uFIsaTNJpR2Ga1qvns1
|
||||
hJQEDMQSLhJvXfBgSkHylRWCpJentr4E3D7mnw5pRsd61Ev9U+uHcdv/WHP4K5hM
|
||||
xsdiwXNXD/RYd1Q1+6bKrCuvnNJVmWe0/RV+r3T8Ni5xdMVFbRWt/VEoE620XX6c
|
||||
a9TQPiA5i/LRVyie+js7Yv+hVjGOlArtuLs6ECQsivfPrqKLOBRWcofKdcf+4N2e
|
||||
3cieUqwzC15C31vcMliD9Hax9c1iuTt9Q3Xzo20fOSazAnQ5YBEExyTtrFBwbfQu
|
||||
ku6hp81pAoGBAN6bc6iJtk5ipYpsaY4ZlbqdjjG9KEXB6G1MExPU7SHXOhOF0cDH
|
||||
/pgMsv9hF2my863MowsOj3OryVhdQhwA6RrV263LRh+JU8NyHV71BwAIfI0BuVfj
|
||||
6r24KudwtUcvMr9pJIrJyMAMaw5ZyNoX7YqFpS6fcisSJYdSBSoxzrzVAoGBANu6
|
||||
xVeMqGavA/EHSOQP3ipDZ3mnWbkDUDxpNhgJG8Q6lZiwKwLoSceJ8z0PNY3VetGA
|
||||
RbqtqBGfR2mcxHyzeqVBpLnXZC4vs/Vy7lrzTiHDRZk2SG5EkHMSKFA53jN6S/nJ
|
||||
JWpYZC8lG8w4OHaUfDHFWbptxdGYCgY4//sjeiuXAoGBANuhurJ99R5PnA8AOgEW
|
||||
4zD1hLc0b4ir8fvshCIcAj9SUB20+afgayRv2ye3Dted1WkUL4WYPxccVhLWKITi
|
||||
rRtqB03o8m3pG3kJnUr0LIzu0px5J/o8iH3ZOJOTE3iBa+uI/KHmxygc2H+XPGFa
|
||||
HGeAxuJCNO2kAN0Losbnz5dlAoGAVsCn94gGWPxSjxA0PC7zpTYVnZdwOjbPr/pO
|
||||
LDE0cEY9GBq98JjrwEd77KibmVMm+Z4uaaT0jXiYhl8pyJ5IFwUS13juCbo1z/u/
|
||||
ldMoDvZ8/R/MexTA/1204u/mBecMJiO/jPw3GdIJ5phv2omHe1MSuSNsDfN8Sbap
|
||||
gmsgaiMCgYB/nrTk89Fp7050VKCNnIt1mHAcO9cBwDV8qrJ5O3rIVmrg1T6vn0aY
|
||||
wRiVcNacaP+BivkrMjr4BlsUM6yH4MOBsNhLURiiCL+tLJV7U0DWlCse/doWij4U
|
||||
TKX6tp6oI+7MIJE6ySZ0cBqOiydAkBePZhu57j6ToBkTa0dbHjn1WA==
|
||||
-----END RSA PRIVATE KEY-----'''
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
form_values = {
|
||||
'form_url': '/compte/connexion',
|
||||
'form_attrs': { 'id': 'new_account' },
|
||||
'post_fields': ['account[login]', 'account[password]'],
|
||||
'username_field': 'account[login]',
|
||||
'password_field': 'account[password]',
|
||||
}
|
||||
|
||||
|
||||
from mandaye.auth.saml2 import SAML2Auth
|
||||
from mandaye.configs import saml2 as saml2_config
|
||||
|
||||
auth = SAML2Auth(form_values, 'linuxfr', saml2_config)
|
||||
|
||||
|
||||
linuxfr_mapping = [
|
||||
{
|
||||
'path': r'/mandaye/logout',
|
||||
'on_response': [{
|
||||
'filter': auth.logout,
|
||||
},]
|
||||
},
|
||||
{
|
||||
'path': r'/mandaye/login$',
|
||||
'method': 'GET',
|
||||
'response': [{
|
||||
'filter': auth.login,
|
||||
'values': {
|
||||
'associate_url': '/mandaye/associate',
|
||||
},
|
||||
'condition': 'response.code==302',
|
||||
},]
|
||||
},
|
||||
{
|
||||
'path': r'/mandaye/sso$',
|
||||
'method': 'GET',
|
||||
'response': [{
|
||||
'filter': auth.sso,
|
||||
'values': {
|
||||
'next_url': '/mandaye/login',
|
||||
'metadata_url': '/mandaye/metadata',
|
||||
}
|
||||
}]
|
||||
},
|
||||
{
|
||||
'path': r'%s$' % saml2_config.END_POINTS_PATH['metadata'],
|
||||
'method': 'GET',
|
||||
'on_response': [{
|
||||
'filter': auth.metadata,
|
||||
}]
|
||||
},
|
||||
{
|
||||
'path': r'%s' % saml2_config.END_POINTS_PATH['single_sign_on_post'],
|
||||
'method': 'POST',
|
||||
'response': [{
|
||||
'filter': auth.single_sign_on_post,
|
||||
}]
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
import config
|
||||
|
||||
from mandaye.views import homepage, logout
|
||||
from urlparse import parse_qs
|
||||
|
||||
import lasso
|
||||
from authentic2.saml import saml2utils
|
||||
|
||||
import session_utils
|
||||
import utils
|
||||
|
||||
from mandaye.response import _302, _500
|
||||
from mandaye.log import logger
|
||||
|
||||
from template import serve_template
|
||||
from http import HTTPResponse, HTTPHeader
|
||||
|
||||
metadata_map = (
|
||||
('AssertionConsumerService',
|
||||
lasso.SAML2_METADATA_BINDING_POST ,
|
||||
'/singleSignOnPost'),
|
||||
)
|
||||
metadata_options = { 'key': config.SAML_SIGNATURE_PUBLIC_KEY }
|
||||
|
||||
class SAML2:
|
||||
|
||||
def sso(self, env, values, request, response):
|
||||
target_idp = None
|
||||
metadata_file_path = None
|
||||
if config.AUTO_IDP:
|
||||
target_idp, metadata_file_path = config.AUTO_IDP
|
||||
if not os.path.isfile(metadata_file_path):
|
||||
return _500('sso', 'Metadata file not found for %s.' % target_idp)
|
||||
else:
|
||||
return _500('sso', 'Unable to load provider.')
|
||||
logger.debug('sso: target_idp is %s' % target_idp)
|
||||
logger.debug('sso: metadata file path is %s' % metadata_file_path)
|
||||
logger.debug('sso: mandaye metadata are %s' % get_metadata())
|
||||
server = lasso.Server.newFromBuffers(get_metadata(),
|
||||
config.SAML_SIGNATURE_PRIVATE_KEY)
|
||||
if not server:
|
||||
return _500('sso', 'Error creating server object.')
|
||||
logger.debug('sso: mandaye server object created')
|
||||
server.addProvider(lasso.PROVIDER_ROLE_IDP, metadata_file_path)
|
||||
login = lasso.Login(server)
|
||||
if not login:
|
||||
return _500('sso', 'Error creating login object.')
|
||||
http_method = config.AUTHNREQ_HTTP_METHOD
|
||||
try:
|
||||
login.initAuthnRequest(target_idp, http_method)
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error initiating request.', error)
|
||||
login.request.nameIDPolicy.format = config.SAML2_NAME_IDENTIFIER_FORMAT
|
||||
login.request.nameIDPolicy.allowCreate = config.ALLOW_CREATE
|
||||
login.request.nameIDPolicy.spNameQualifier = config.SP_NAME_QUALIFIER
|
||||
login.request.protocolBinding = config.AUTHNRESP_BINDING
|
||||
try:
|
||||
login.buildAuthnRequestMsg()
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error initiating request.', error)
|
||||
logger.debug('sso: set request id in session %s' % login.request.iD)
|
||||
session_utils.set_item_in_session(env, 'request_id', login.request.iD)
|
||||
env['beaker.session']['unique_id'] = login.request.iD
|
||||
env['beaker.session'].save()
|
||||
|
||||
ipy.msgUrl:
|
||||
return _500('sso', 'Enable to perform sso by redirection.')
|
||||
return _302(login.msgUrl)
|
||||
|
||||
def logout(self, env, values, request, response):
|
||||
logout(env)
|
||||
|
||||
def single_sign_on_post(self, env, values, request, response):
|
||||
target_idp = None
|
||||
metadata_file_path = None
|
||||
if config.AUTO_IDP:
|
||||
target_idp, metadata_file_path = config.AUTO_IDP
|
||||
else:
|
||||
return _500('singleSignOnPost', 'Unable to load provider.')
|
||||
server = lasso.Server.newFromBuffers(get_metadata(),
|
||||
config.SAML_SIGNATURE_PRIVATE_KEY)
|
||||
if not server:
|
||||
return _500('singleSignOnPost', 'Error creating server object.')
|
||||
server.addProvider(lasso.PROVIDER_ROLE_IDP, metadata_file_path)
|
||||
login = lasso.Login(server)
|
||||
if not login:
|
||||
return _500('singleSignOnPost', 'Error creating login object.')
|
||||
|
||||
if env['REQUEST_METHOD'] != 'POST':
|
||||
return _500('singleSignOnPost', 'Not a POST request.')
|
||||
|
||||
msg = env['wsgi.input']
|
||||
params = parse_qs(msg.read())
|
||||
if not params or not lasso.SAML2_FIELD_RESPONSE in params.keys():
|
||||
return _500('singleSignOnPost', 'Missing response.')
|
||||
message = params[lasso.SAML2_FIELD_RESPONSE][0]
|
||||
logger.debug('sso: message posted %s' % message)
|
||||
|
||||
try:
|
||||
login.processAuthnResponseMsg(message)
|
||||
except:
|
||||
return _500('singleSignOnPost', 'Unable to proces authnresponse message.')
|
||||
|
||||
subject_confirmation = utils.get_absolute_uri(env)
|
||||
saml_request_id = session_utils.get_item_in_session(env, 'request_id')
|
||||
check = saml2utils.authnresponse_checking(login, subject_confirmation,
|
||||
logger, saml_request_id=saml_request_id)
|
||||
if not check:
|
||||
return _500('singleSignOnPost', 'error checking authn response %s' % env)
|
||||
logger.debug('sso: response successfully checked')
|
||||
|
||||
try:
|
||||
login.acceptSso()
|
||||
except lasso.Error, error:
|
||||
return _500('sso', 'Error validating sso.', error)
|
||||
logger.debug('sso: sso accepted, session validation')
|
||||
|
||||
session_utils.validate_session(env)
|
||||
attributes = saml2utils.get_attributes_from_assertion(login.assertion,
|
||||
logger)
|
||||
session_utils.set_item_in_session(env, 'attributes', attributes)
|
||||
|
||||
return _302('/')
|
||||
|
||||
def _get_metadata():
|
||||
metagen = saml2utils.Saml2Metadata(config.PROXY_SAML2_ENTITYID,
|
||||
url_prefix = config.SAML2_EP_BASE)
|
||||
metagen.add_sp_descriptor(metadata_map, metadata_options)
|
||||
return str(metagen)
|
||||
|
||||
def metadata(self, env, values, request, response):
|
||||
title='metadata'
|
||||
headers = HTTPHeader({'Content-Type': ['text/xml']})
|
||||
return HTTPResponse(200, 'Found', headers,
|
||||
get_metadata())
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
def validate_session(env):
|
||||
env['beaker.session']['validated'] = True
|
||||
|
||||
def invalidate_session(env):
|
||||
env['beaker.session']['validated'] = False
|
||||
|
||||
def is_session_valid(env):
|
||||
if 'validated' in env['beaker.session'] and \
|
||||
env['beaker.session']['validated']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_item_in_session(env, key, value):
|
||||
env['beaker.session'][key] = value
|
||||
|
||||
def get_item_in_session(env, key):
|
||||
return env['beaker.session'].get(key)
|
||||
|
||||
def del_item_in_session(env, key):
|
||||
if key in env['beaker.session']:
|
||||
del env['beaker.session'][key]
|
|
@ -0,0 +1,498 @@
|
|||
/* theme derived and inspired by TerraFirma
|
||||
* <http://www.oswd.org/design/information/id/3557/>
|
||||
*/
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
body#iframe {
|
||||
background: white;
|
||||
}
|
||||
|
||||
html {
|
||||
background: #F9F9F7 url(../images/a1.gif) repeat-x;
|
||||
color: #44b2cb;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color: #44b2cb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:hover
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
div#wrap {
|
||||
background: white;
|
||||
width: 640px;
|
||||
margin: 5em auto;
|
||||
padding: 15px;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius:6px;
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,0.75);
|
||||
-webkit-box-shadow: 0 0 4px rgba(0,0,0,0.75);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#header
|
||||
{
|
||||
position: absolute;
|
||||
background: url(../images/a8.png) repeat-x;
|
||||
-moz-border-radius: 6px 0 0 6px;
|
||||
-webkit-border-radius: 6px 0 0 6px;
|
||||
width: 450px;
|
||||
height: 92px;
|
||||
color: #fff;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#header h1
|
||||
{
|
||||
font-size: 23px;
|
||||
letter-spacing: -1px;
|
||||
padding-top: 30px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#header span
|
||||
{
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
color: #FCE2CA;
|
||||
}
|
||||
|
||||
#splash
|
||||
{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
background: url(../images/eo.png) no-repeat;
|
||||
width: 153px;
|
||||
height: 92px;
|
||||
-moz-border-radius: 0 6px 6px 0;
|
||||
-webkit-border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
div#content {
|
||||
margin: 1em 1ex;
|
||||
margin-top: 130px;
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
div#content h2 {
|
||||
margin-top: 0;
|
||||
font-weight: normal;
|
||||
color: #656551;
|
||||
font-size: 18px;
|
||||
letter-spacing: -1px;
|
||||
line-height: 25px;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 0 10px 15px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
background: url(../images/a22.gif) bottom repeat-x;
|
||||
}
|
||||
|
||||
#footer
|
||||
{
|
||||
font-size: 70%;
|
||||
position: relative;
|
||||
clear: both;
|
||||
height: 66px;
|
||||
text-align: center;
|
||||
line-height: 66px;
|
||||
background-image: url(../images/a8.png);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#footer a
|
||||
{
|
||||
color: #8C8C73;
|
||||
}
|
||||
|
||||
|
||||
form#login-form p {
|
||||
float: left;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
form#login-form input.submit {
|
||||
float: right;
|
||||
width: 18%;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
div.login-actions {
|
||||
clear: both;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
div.login-actions p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form p {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
form p label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
form p input,
|
||||
form p textarea {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
ul.messages {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul.messages li.error {
|
||||
color: #e80404;
|
||||
}
|
||||
|
||||
ul.errorlist {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #e80404;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
padding: 5px;
|
||||
border: 1px solid #cccccc;
|
||||
color:#666666;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
textarea:focus, input[type="text"]:focus, input[type="password"]:focus {
|
||||
border: 1px solid #4690d6;
|
||||
color:#333333;
|
||||
}
|
||||
|
||||
input[type=submit] {
|
||||
color: #ffffff;
|
||||
background:#4690d6;
|
||||
border: 1px solid #2a567f;
|
||||
font-weight: bold;
|
||||
padding: 2px 8px 2px 8px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
input[type=submit]:hover {
|
||||
border-color: #0e1d2b;
|
||||
}
|
||||
|
||||
form#login-form ul.errorlist {
|
||||
margin-bottom: 1em;
|
||||
width: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* OpenID Stuff */
|
||||
|
||||
#openid_btns, #openid_btns br {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#openid_highlight a {
|
||||
border: 1px solid #888;
|
||||
}
|
||||
|
||||
#openid_input_area input[type=submit] {
|
||||
padding-top: 0;
|
||||
margin-top: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.openid_large_btn {
|
||||
width: 100px;
|
||||
height: 60px;
|
||||
border: 1px solid #DDD;
|
||||
margin: 3px;
|
||||
float: left;
|
||||
}
|
||||
.openid_small_btn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1px solid #DDD;
|
||||
margin: 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
a.openid_large_btn:focus {
|
||||
outline: none;
|
||||
}
|
||||
a.openid_large_btn:focus {
|
||||
-moz-outline-style: none;
|
||||
}
|
||||
.openid_selected {
|
||||
border: 4px solid #DDD;
|
||||
}
|
||||
|
||||
#openid_input_area {
|
||||
clear: both;
|
||||
padding-top: 2.5em;
|
||||
}
|
||||
|
||||
li.indented {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
ul.NoBullet {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
div#content h4 {
|
||||
margin-bottom: 5px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
div#content p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
div.errors {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #e80404;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div#breadcrumb {
|
||||
font-size: 80%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div#user {
|
||||
position: absolute;
|
||||
top: 115px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
a#logout {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
|
||||
.ui-tabs .ui-tabs-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
h4 + div, div#profile {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
div#menu {
|
||||
position: relative;
|
||||
background: #46461F url(../images/a17.gif) repeat-x;
|
||||
height: 67px;
|
||||
padding: 0px 20px 0px 5px;
|
||||
margin: 136px 0px 0px 0px;
|
||||
}
|
||||
|
||||
#menu ul
|
||||
{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#menu ul li
|
||||
{
|
||||
display: inline;
|
||||
line-height: 52px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
#menu ul li.first
|
||||
{
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
#menu ul li a
|
||||
{
|
||||
background-color: transparent;
|
||||
background-repeat: repeat-x;
|
||||
padding: 8px 12px 8px 12px;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
#menu ul li a:hover
|
||||
{
|
||||
background: #fff url(../images/a18.gif) repeat-x top;
|
||||
color: #4A4A24;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#eo
|
||||
{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
line-height: 52px;
|
||||
color: #BDBDA2;
|
||||
right: 30px;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
#eo a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul#tab-nav {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
width: 160px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
ul#tab-nav li {
|
||||
line-height: 300%;
|
||||
position: relative;
|
||||
right: -1px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
ul#tab-nav li.ui-tabs-selected {
|
||||
border: 1px solid #ccc;
|
||||
border-right: 1px solid white;
|
||||
}
|
||||
|
||||
ul#tab-nav a {
|
||||
display: block;
|
||||
padding-left: 1ex;
|
||||
outline: none;
|
||||
-moz-user-focus:ignore;
|
||||
}
|
||||
|
||||
ul#tab-nav a:hover {
|
||||
}
|
||||
|
||||
ul#tab-nav a:active {
|
||||
}
|
||||
|
||||
/* XXX: add a class to divs, so it works in IE */
|
||||
div#tabs > div {
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
width: 420px;
|
||||
padding: 10px;
|
||||
min-height: 26em;
|
||||
}
|
||||
|
||||
a.bigbutton {
|
||||
display: block;
|
||||
-moz-border-radius: 6px;
|
||||
-webkit-border-radius:6px;
|
||||
border: 1px solid black;
|
||||
margin: 2em 0;
|
||||
line-height: 300%;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
-webkit-box-shadow: 0 0 4px rgba(0,0,0,0.75);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,0.75);
|
||||
}
|
||||
|
||||
a.bigbutton:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
div#providers {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#modalOverlay {
|
||||
height:100%;
|
||||
width:100%;
|
||||
position:fixed;
|
||||
left:0;
|
||||
top:0;
|
||||
z-index:3000;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
cursor:wait;
|
||||
}
|
||||
|
||||
div#popup {
|
||||
display: none;
|
||||
position:fixed;
|
||||
width:500px;
|
||||
left:50%;
|
||||
margin-left:-250px;
|
||||
z-index:3100;
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
div#popup div {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
border-color: #333 black black #333;
|
||||
}
|
||||
|
||||
div#popup h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#popup ul {
|
||||
max-height: 70px;
|
||||
overflow: auto;
|
||||
margin: 0 1em 1em 1em;
|
||||
padding: 0 1em 1em 1em;
|
||||
}
|
||||
|
||||
div#popup h3 {
|
||||
margin-bottom: 4px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
div#popup p {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
div#popup a#close {
|
||||
float: right;
|
||||
padding: 1ex;
|
||||
}
|
||||
|
||||
a.roleid_button {
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
background: #5C5C5C;
|
||||
color: #44b2cb;
|
||||
font-weight: bold;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.roleid_button:hover {
|
||||
background: black;
|
||||
}
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 407 B |
After Width: | Height: | Size: 158 B |
After Width: | Height: | Size: 43 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 295 B |
After Width: | Height: | Size: 222 B |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 666 B |
After Width: | Height: | Size: 781 B |
|
@ -11,5 +11,4 @@ def serve_template(templatename, **kwargs):
|
|||
""" serve a template
|
||||
"""
|
||||
mytemplate = mylookup.get_template(templatename)
|
||||
return mytemplate.render_unicode(**kwargs)
|
||||
|
||||
return mytemplate.render_unicode(**kwargs).encode('utf-8', 'replace')
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="/static/css/style.css" />
|
||||
<title>${title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="header">
|
||||
<h1>Mandaye</h1>
|
||||
<span>seamless SSO...</span>
|
||||
</div>
|
||||
<div id="splash"></div>
|
||||
<div id="content">
|
||||
<h1>${title}</h1>
|
||||
<p><a href='logout'>Logout</a></p>
|
||||
% if nameid and issuer:
|
||||
<p>You are known as <strong>${nameid}</strong> from <strong>${issuer}</strong></p>
|
||||
% if attributes:
|
||||
<p>What we now about you is <strong>${attributes}</strong></p>
|
||||
% endif
|
||||
% else:
|
||||
<p>The user is logged but the user nameid en issuer id are missing.</p>
|
||||
% endif
|
||||
</div>
|
||||
<div id="footer">
|
||||
Copyright © 2013 Entr'ouvert
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +1,24 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>${title}</title>
|
||||
<head>
|
||||
<link rel="stylesheet" href="/static/css/style.css" />
|
||||
<title>${title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${title}</h1>
|
||||
<p>${body}</p>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div id="header">
|
||||
<h1>Mandaye</h1>
|
||||
<span>seamless SSO...</span>
|
||||
</div>
|
||||
<div id="splash"></div>
|
||||
<div id="content">
|
||||
<h1>${title}</h1>
|
||||
<p>${body}</p>
|
||||
<p><a href='/'>Back to home</a></p>
|
||||
</div>
|
||||
<div id="footer">
|
||||
Copyright © 2013 Entr'ouvert
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>${title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${title}</h1>
|
||||
<p>${body}</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,3 @@
|
|||
def get_absolute_uri(env):
|
||||
return env['mandaye.scheme'] + '://' + env['HTTP_HOST'] + \
|
||||
env['PATH_INFO']
|
|
@ -0,0 +1,43 @@
|
|||
import config
|
||||
import session_utils
|
||||
import saml2_endpoints
|
||||
|
||||
from http import HTTPResponse, HTTPHeader
|
||||
from template import serve_template
|
||||
|
||||
from mandaye.log import logger
|
||||
|
||||
def homepage(env):
|
||||
title='Mandaye homepage'
|
||||
headers = HTTPHeader({'Content-Type': ['text/html']})
|
||||
if not config.SAML2_SUPPORT:
|
||||
return HTTPResponse(200, 'Found', headers,
|
||||
serve_template("response.html",
|
||||
title=title, body='SAML2 not available'))
|
||||
|
||||
if not session_utils.is_session_valid(env):
|
||||
return saml2_endpoints.sso(env)
|
||||
|
||||
attributes = session_utils.get_item_in_session(env, 'attributes')
|
||||
|
||||
nameid = None
|
||||
issuer = None
|
||||
if attributes:
|
||||
nameid = attributes.get('__nameid')
|
||||
issuer = attributes.get('__issuer')
|
||||
|
||||
return HTTPResponse(200, 'Found', headers,
|
||||
serve_template("homepage.html",
|
||||
title=title, nameid=nameid, issuer=issuer, attributes=attributes))
|
||||
|
||||
def logout(env):
|
||||
if not session_utils.is_session_valid(env):
|
||||
result = "You were not loggeg in."
|
||||
else:
|
||||
session_utils.invalidate_session(env)
|
||||
result = "You are now logged out."
|
||||
title='Logout page'
|
||||
headers = HTTPHeader({'Content-Type': ['text/html']})
|
||||
return HTTPResponse(200, 'Found', headers,
|
||||
serve_template("response.html",
|
||||
title=title, body=result))
|
|
@ -65,10 +65,10 @@ def main():
|
|||
repository=mandaye.migration.__path__[0])
|
||||
logger.info("Database created")
|
||||
if options.cryptpwd:
|
||||
from mandaye.config.backend import ManagerSPUserSQL
|
||||
for user in ManagerSPUserSQL.all():
|
||||
from mandaye.config.backend import ManagerSPUser
|
||||
for user in ManagerSPUser.all():
|
||||
user.password = encrypt_pwd(user.password)
|
||||
ManagerSPUserSQL.save()
|
||||
ManagerSPUser.save()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|