This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
authentic-old/authentic/liberty/root.ptl

1510 lines
65 KiB
Plaintext

import os
import re
import urllib
import httplib
import Cookie
import socket
import datetime
import lasso
if hasattr(lasso, 'ProfileService') and not hasattr(lasso, 'DataService'):
lasso.DataService = lasso.ProfileService
from quixote import get_request, get_response, redirect, get_field, get_publisher
from quixote.directory import Directory, AccessControlled
from quixote.http_request import parse_header
from quixote import get_user, get_session, get_session_manager
from qommon import get_cfg, get_logger
from qommon import template
from qommon import errors
from qommon.storage import StorableObject
from qommon.publisher import sitecharset2utf8
import authentic
import authentic.identities
from authentic.misc import get_lasso_server, get_provider_key, redirect_with_return_url
from authentic.form import *
import authentic.login_token as login_token
import common
import qommon.soap as soap
BENCH = False
class Artifact(StorableObject):
_names = 'artifacts'
_indexes = ['artifact']
artifact = None
session_id = None
provider_id = None
def get_by_artifact(cls, artifact):
return cls.get(artifact)
get_by_artifact = classmethod(get_by_artifact)
class SpDir(Directory):
def _q_lookup(self, component):
return SpUI(component)
class RootDirectory(common.LassoDirectory):
_q_exports = ["", "sp", "singleSignOn", "failSingleSignOn", "soapEndpoint",
'metadata', ('metadata.xml', 'metadata'), 'public_key',
"singleLogout", "singleLogoutReturn", "federationTermination",
"federationTerminationReturn", "registerNameIdentifier", "consent",
"proxySoapEndpoint", "proxyAssertionConsumer", "proxySingleLogout",
"proxySingleLogoutNext", 'proxySingleLogoutReturn']
sp = SpDir()
def _q_index(self):
raise errors.AccessError()
def singleSignOn(self):
'''Handle an AuthnRequest, if not logged and
interaction is authorized, ask for login'''
return self.single_sign_on()
def failSingleSignOn(self):
'''Handle an AuthnRequest, but always return
RequestDenied'''
return self.single_sign_on(request_denied = True)
def single_sign_on(self, request_denied = False):
server = get_lasso_server()
if not server:
return template.error_page(_('Liberty support not yet configured.'))
login = lasso.Login(server)
request = get_request()
authn_request_msg = None
if request.get_method() == 'GET':
if lasso.isLibertyQuery(request.get_query()):
authn_request_msg = request.get_query()
if BENCH:
authn_request_msg = 'RequestID=_CED73573A277216F1F1D046F5155D607&MajorVersion=1&MinorVersion=2&IssueInstant=2006-01-24T10%3A19%3A15Z&ProviderID=http%3A%2F%2Funwind%2Fliberty%2Fmetadata&ForceAuthn=false&IsPassive=false&NameIDPolicy=federated&consent=urn%3Aliberty%3Aconsent%3Aobtained&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=kfu2VYPIiSS%2FGGDdVKxiSd%2F%2Fe8XN6vAPZkf8TxXzNzuEqLKBGQsRQTv4waaDHBYMRmSMOHd81ZpDbc6lqOZLkUdv68QCjMIvF3L53S0V7Mab8PDs2%2B6lNEmuUOn%2F2hwoJ2ol6%2B%2BCKtpIq3xksh8juyyrZgMyjhopGTzmXCwFIhokUFuHD4SX8YC%2BYkFNyDnnD2acU3Id2ip2zmabO6WYh7VOvYSxBl4BtYRWLZ%2BmdZTM0LOUn%2FpSEUAwXi9bmCphdzgxQUd8T5BfRflvBmP%2BMUNSalmsvLwXk15eiVDGbxcmikVsNGpSy0nwQOoCMCgFJC60QeoClmpVjgRfILWBrg%3D%3D'
else: # method is POST
authn_request_msg = get_field('LAREQ')
if not authn_request_msg:
return template.error_page(_('No authentication request found.'))
try:
login.processAuthnRequestMsg(authn_request_msg)
except lasso.Error, error:
if error[0] == lasso.SERVER_ERROR_PROVIDER_NOT_FOUND:
return template.error_page(_('Request initiated by an unaffiliated provider.'))
if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
return template.error_page(_('Failed to check authentication request signature.'))
if error[0] == lasso.DS_ERROR_SIGNATURE_NOT_FOUND:
return template.error_page(_('Authentication request is not signed.'))
raise
get_logger().info('SSO from %s' % login.remoteProviderId)
request_id = login.request.requestId
session = get_session()
if BENCH:
session.user = 'fred'
session.id = 'SESSION-DE-TEST'
if session and session.user and not session.lasso_session_dump:
# user has a session but it was only created locally, so it has no
# assertion. However login.mustAuthenticate() will look for an
# existing session to decide whether to ask for login or not. So
# we needs to feed an empty session to the login object. Note that
# Lasso doesn't do any namespace checking.
login.setSessionFromDump('<Session xmlns="http://www.entrouvert.org/namespaces/lasso/0.0" Version="1"/>')
if session and session.lasso_session_dump:
login.setSessionFromDump(session.lasso_session_dump)
if request_denied:
user_authenticated = False
elif login.mustAuthenticate() and not login_token.LoginToken.has_good_authentication(request_id):
# We use a login token to verify ForceAuthn
login_token.LoginToken(request_id).store()
self.sso_before_login_redirect()
login_url = request.environ['SCRIPT_NAME'] + '/login'
return redirect_with_return_url(login_url,
(('okURL', get_request().get_local_url()),
('cancelURL', get_request().get_local_url().replace('singleSignOn','failSingleSignOn')),
('LoginToken', request_id)))
else:
if session and session.user:
user_authenticated = True
else:
user_authenticated = False
return self.sso_after_authentication(login, user_authenticated)
def sso_before_login_redirect(self):
pass # to be subclassed
def consent [html] (self):
form = Form(enctype="multipart/form-data", id = "login")
form.add_submit("consent", _("Consent to Federation"))
form.add_submit("refuse", _("Refuse Federation"))
if not form.is_submitted() or form.has_errors():
template.html_top()
"""<div id="login-top"><h1>%s</h1></div>
<div id="login-form">""" % _('Login')
# XXX: get site name from provider/metadata/organization to have
# an appropriate question.
"<p>%s</p>" % _('Do you consent to federate your account with the other site?')
form.render()
'</div>'
else:
if form.get_widget('consent').parse():
consent = True
else:
consent = False
session = get_session()
login = lasso.Login.newFromDump(get_lasso_server(), session.lasso_login_dump)
session.lasso_login_dump = None
return self.sso_after_consent(login, True, consent)
def sso_after_authentication(self, login, user_authenticated, proxied = False):
# part 2 of SSO: user has been authenticated (or not)
session, identity = self.restore_user_details(login)
consent_obtained = False
if user_authenticated:
if login.mustAskForConsent():
session.lasso_login_dump = login.dump()
return redirect('consent')
return self.sso_after_consent(login, user_authenticated, True, proxied)
def restore_user_details(self, login):
authentic.identities.get_store().load_identities()
session = get_session()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
identity = None
if identity and identity.lasso_dump:
login.setIdentityFromDump(identity.lasso_dump)
if session and session.lasso_session_dump:
login.setSessionFromDump(session.lasso_session_dump)
return (session, identity)
def sso_after_consent(self, login, user_authenticated, consent_obtained, proxied = False):
# part 3 of SSO: if necessary, user has given its consent
session, identity = self.restore_user_details(login)
try:
login.validateRequestMsg(user_authenticated, consent_obtained)
except lasso.Error, error:
if error[0] < 0:
raise
do_federation = False
else:
do_federation = True
if not BENCH and lasso.WSF_SUPPORT:
if identity:
if not identity.resource_id:
identity.resource_id = '%s/resources/identity/%s' % (
get_cfg('idp')['base_url'], identity.id)
authentic.identities.get_store().save(identity)
login.setResourceId(identity.resource_id)
authn_methods = {
'password': lasso.SAML_AUTHENTICATION_METHOD_PASSWORD,
'password-on-https': lasso.SAML_AUTHENTICATION_METHOD_PASSWORD,
'password-and-ip': 'urn:oasis:names:tc:SAML:1.0:am:InternetProtocolPassword',
'client-certificate': lasso.SAML_AUTHENTICATION_METHOD_SOFTWARE_PKI
}
auth_method = authn_methods.get(session.authentication_method or 'password')
if proxied:
# XXX: if sso is proxied, build it with the same details as
# the proxied assertion
# (current condition looks ridiculous, I know)
login.buildAssertion(auth_method, None, None, None, None)
else:
now = datetime.datetime.utcnow()
notBefore = now-datetime.timedelta(0,60)
notOnOrAfter = now+datetime.timedelta(0,60)
login.buildAssertion(auth_method,
get_session().authentication_instant.isoformat()+'Z',
None,
notBefore.isoformat()+'Z',
notOnOrAfter.isoformat()+'Z')
try:
identity = authentic.identities.get_store().get_identity(get_session().user)
except KeyError:
identity = None
login.assertion.authenticationStatement.sessionIndex = login.assertion.assertionId
common.SessionIndex(login.assertion.assertionId).store()
if identity and hasattr(identity, 'attributes') and identity.attributes:
t = lasso.NodeList()
if login.assertion.attributeStatement:
for at in login.assertion.attributeStatement.attribute:
t.append(at)
login.assertion.attributeStatement = lasso.SamlAttributeStatement()
for k, v in identity.attributes.items():
ta = lasso.SamlAttribute()
t.append(ta)
ta.attributeName = k
ta.attributeNamespace = 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic'
t2 = lasso.NodeList()
for vi in v:
tav = lasso.SamlAttributeValue()
t2.append(tav)
t3 = lasso.NodeList()
ttn = lasso.MiscTextNode()
if type(vi) is unicode:
ttn.content = vi.encode('utf-8')
else:
ttn.content = sitecharset2utf8(vi)
ttn.text_child = True
t3.append(ttn)
tav.any = t3
ta.attributeValue = t2
login.assertion.attributeStatement.attribute = t
if login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_ART:
login.buildArtifactMsg(lasso.HTTP_METHOD_REDIRECT)
elif login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_POST:
login.buildAuthnResponseMsg()
else:
return template.error_page(_('Unknown liberty protocol profile'))
if do_federation and identity:
if login.isIdentityDirty:
identity.lasso_dump = login.identity.dump()
authentic.identities.get_store().save(identity)
if login.nameIdentifier:
# not there if not authenticated or consent not granted
if not session.name_identifiers:
session.name_identifiers = []
session.name_identifiers.append(login.nameIdentifier.content)
if login.isSessionDirty:
session.lasso_session_dump = login.session.dump()
self.handle_common_domain_cookie(login)
if login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_ART:
artifact = Artifact(id = login.assertionArtifact)
artifact.artifact = login.assertionArtifact
artifact.session_id = session.id
artifact.provider_id = login.remoteProviderId
artifact.store()
return redirect(login.msgUrl)
else:
return self.postTo(login.msgUrl, login.msgBody, 'LARES',
relay_state=login.relayState,
title=N_('Authentication Response'))
def handle_common_domain_cookie(self, login):
get_publisher().reload_cfg()
try:
common_domain = get_cfg('idp')['common_domain']
except KeyError:
common_domain = None
if common_domain:
request = get_request()
try:
intro_cookie = request.cookies['_liberty_idp']
except KeyError:
intro_cookie = ''
splitted_cookie = [x.strip() for x in intro_cookie.split(' ') if x]
succinct_id = login.server.getBase64SuccinctId()
if succinct_id in splitted_cookie:
splitted_cookie.remove(succinct_id)
splitted_cookie.append(succinct_id)
response = get_response()
new_cookie = ' '.join(splitted_cookie)
if new_cookie != intro_cookie:
response.set_cookie('_liberty_idp', new_cookie,
domain = '.' + common_domain, path = '/',
expires = Cookie._getdate(3*365*86400))
@common.soap_endpoint
def soapEndpoint(self):
soap_message = self.get_soap_message()
authentic.identities.get_store().load_identities()
request_type = lasso.getRequestTypeFromSoapMsg(soap_message)
if request_type == lasso.REQUEST_TYPE_LOGIN:
login = lasso.Login(get_lasso_server())
login.processRequestMsg(soap_message)
artifact = None
try:
artifact = Artifact.get_by_artifact(login.assertionArtifact)
except KeyError:
provider_id = None
else:
artifact.remove_self()
provider_id = artifact.provider_id
session = get_session_manager().get(artifact.session_id)
if session: # it should always be there but who knows...
login.setSessionFromDump(session.lasso_session_dump)
try:
login.buildResponseMsg(provider_id)
get_logger().info('Artifact resolve from provider %s for artifact %s' % (provider_id, login.assertionArtifact))
except lasso.Error, error:
if error[0] == lasso.DS_ERROR_SIGNATURE_VERIFICATION_FAILED:
get_logger().warn('Signature verification failed on artifact resolve from %s)' % provider_id)
elif error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
if not artifact:
get_logger().warn('Could not find the artifact on artifact resolve from %s, artifact %s)' % (provider_id, login.assertionArtifact))
else:
get_logger().warn('Could not find a session dump on artifact resolve from %s, artifact %s)' % (provider_id, login.assertionArtifact))
else:
raise
if login.isSessionDirty:
if login.session:
session.lasso_session_dump = login.session.dump()
else:
session.lasso_session_dump = None
get_session_manager().commit_changes(session)
return login.msgBody
if request_type == lasso.REQUEST_TYPE_LOGOUT:
logout = lasso.Logout(get_lasso_server())
logout.processRequestMsg(soap_message)
name_identifier = logout.nameIdentifier.content
try:
session_index = common.SessionIndex.get(logout.request.sessionIndex)
logout_session = get_session_manager().get(session_index.session_id)
except KeyError:
# no session, build straight failure answer
logout.buildResponseMsg()
return logout.msgBody
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
pass
else:
if identity.lasso_dump:
logout.setIdentityFromDump(identity.lasso_dump)
if session.proxied_idp:
try:
self.proxy_slo_soap(session, identity)
except lasso.Error, error:
if error[0] == lasso.LOGOUT_ERROR_UNSUPPORTED_PROFILE:
pass
# too bad but we won't fallback to HTTP redirect for
# the sake of the IdP
logout.setSessionFromDump(session.lasso_session_dump)
try:
logout.validateRequest()
except lasso.Error, error:
if error[0] == lasso.LOGOUT_ERROR_UNSUPPORTED_PROFILE:
pass
elif error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
pass
else:
raise
else:
session_manager = get_session_manager()
del session_manager[session_index.session_id]
remote_provider_id = logout.getNextProviderId()
while remote_provider_id:
try:
logout.initRequest(remote_provider_id, lasso.HTTP_METHOD_SOAP)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND:
break # this is bad, abort.
if error[0] == lasso.LOGOUT_ERROR_UNSUPPORTED_PROFILE:
get_logger().warn('SLO not supported on %s' % remote_provider_id)
break # this doesn't happen with newer Lasso releases
if error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
get_logger().warn('SLO not supported on %s' % remote_provider_id)
break # this doesn't happen with newer Lasso releases
raise
logout.buildRequestMsg()
try:
soap_answer = self.soap_call(logout.msgUrl, logout.msgBody)
logout.processResponseMsg(soap_answer)
except soap.SOAPException:
pass # log ?
except lasso.Error, error:
pass # log ?
remote_provider_id = logout.getNextProviderId()
logout.buildResponseMsg()
return logout.msgBody
if request_type == lasso.REQUEST_TYPE_DEFEDERATION:
defederation = lasso.Defederation(get_lasso_server())
defederation.processNotificationMsg(soap_message)
name_identifier = defederation.nameIdentifier.content
identity = authentic.identities.get_store().get_identity_for_name_identifier(name_identifier)
for session in get_session_manager().values():
if name_identifier in (session.name_identifiers or []):
get_logger().info('FedTerm/SOAP from %s' % logout.remoteProviderId)
break
else:
session = None
if session and session.proxied_idp:
pass # XXX: fedterm with IdP
return self.fedterm(defederation, identity, session)
if request_type == lasso.REQUEST_TYPE_NAME_REGISTRATION:
registration = lasso.NameRegistration(get_lasso_server())
registration.processRequestMsg(soap_message)
oldNameIdentifier = registration.oldNameIdentifier.content
identity = authentic.identities.get_store().get_identity_for_name_identifier(
oldNameIdentifier)
for session in get_session_manager().values():
if oldNameIdentifier in (session.name_identifiers or []):
break
return self.rni(registration, identity, session)
idsis_pp = get_cfg('idp').get('idsis_pp', False)
if request_type == lasso.REQUEST_TYPE_DISCO_QUERY and lasso.WSF_SUPPORT:
server = get_lasso_server()
disco = lasso.Discovery(server)
disco.processQueryMsg(soap_message)
try:
identity = self.get_identity_by_resource_id(disco.resourceId)
disco.setIdentityFromDump(identity.lasso_dump)
except:
pass
disco.buildResponseMsg()
return disco.msgBody
if request_type == lasso.REQUEST_TYPE_DISCO_MODIFY and lasso.WSF_SUPPORT:
server = get_lasso_server()
disco = lasso.Discovery(server)
disco.processModifyMsg(soap_message, None)
try:
identity = self.get_identity_by_resource_id(disco.resourceId)
disco.setIdentityFromDump(identity.lasso_dump)
except:
pass
disco.buildModifyResponseMsg()
if disco.isIdentityDirty:
identity.lasso_dump = disco.identity.dump()
authentic.identities.get_store().save(identity)
return disco.msgBody
if request_type == lasso.REQUEST_TYPE_DST_QUERY and lasso.WSF_SUPPORT:
service = lasso.DataService(get_lasso_server())
# XXX: lasso lacks a function to get the dst namespace
try:
service_prefix = re.findall('<([a-z]*?):Query>', soap_message)[0]
service_href = re.findall('xmlns:%s="(.*?)"' % service_prefix, soap_message)[0]
except IndexError: # too bad, this hacky thing didn't work.
service_href = lasso.PP_HREF
if service_href == lasso.PP_HREF and not idsis_pp:
pass # XXX: build deny request
return 'ERROR'
service.processQueryMsg(soap_message)
try:
identity = self.get_identity_by_resource_id(service.resourceId)
except:
pass # XXX: build deny request ?
resource = identity.get_dst_view(service_href)
if resource:
service.resourceData = identity.get_dst_view(service_href)
else:
return 'ERROR' # XXX: build deny request
service.buildResponseMsg()
return service.msgBody
def get_identity_by_resource_id(self, resource_id):
resource = resource_id.content
prefix = '%s/resources/' % get_cfg('idp')['base_url']
if not resource.startswith(prefix):
raise "unknown resource"
resource = resource[len(prefix):]
type, value = resource.split('/')
if type != 'identity': # we only know identities as resource
raise "resource not identity"
try:
identity = authentic.identities.get_store().get_identity(value)
except KeyError:
raise "identity not found"
if lasso.WSF_SUPPORT:
idsis_pp = get_cfg('idp').get('idsis_pp', False)
lasso_identity = lasso.Identity.newFromDump(identity.lasso_dump)
server = authentic.misc.get_lasso_server()
offerings = lasso_identity.getOfferings(lasso.PP_HREF)
if offerings:
lst = [x for x in lasso_identity.getOfferings(lasso.PP_HREF) if \
x.serviceInstance.providerId == server.providerId]
else:
lst = []
if idsis_pp and len(lst) == 0:
# adds authentic id-sis pp offering
resource_offering = lasso.DiscoResourceOffering(self.get_pp_service())
resource_offering.resourceId = lasso.DiscoResourceID(identity.resource_id)
resource_offering.abstract = "Personal Profile with Authentic informations"
lasso_identity.addResourceOffering(resource_offering)
identity.lasso_dump = lasso_identity.dump()
authentic.identities.get_store().save(identity)
elif not idsis_pp and len(lst) > 0:
# remove authentic id-sis pp offerings
try:
for x in lst:
lasso_identity.removeResourceOffering(x.entryId)
except:
pass # ignores everything since it would raise an exception even on success
identity.lasso_dump = lasso_identity.dump()
authentic.identities.get_store().save(identity)
return identity
def get_pp_service(self):
server = authentic.misc.get_lasso_server()
return lasso.DiscoServiceInstance(
lasso.PP_HREF,
server.providerId,
lasso.DiscoDescription_newWithBriefSoapHttpDescription(
lasso.SECURITY_MECH_NULL,
'%s/soapEndpoint' % get_cfg('idp', {}).get('base_url', None)))
def singleLogout(self):
request = get_request()
if lasso.isLibertyQuery(request.get_query()):
return self.slo_sp()
else:
session = get_session()
# TODO: settings for logout type (soap/get/redirect)
return self.slo_idp(session)
def slo_idp(self, session, method = None):
# Single Logout initiated by IdP
if not session or not session.user:
raise errors.AccessError()
# delog user
user = session.user
session.user = None
session.store()
if not session.lasso_session_dump:
if method == lasso.HTTP_METHOD_SOAP:
return
return redirect(get_request().environ['SCRIPT_NAME'] + '/logout')
logout = lasso.Logout(get_lasso_server())
logout.setSessionFromDump(session.lasso_session_dump)
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(user)
except KeyError:
if method == lasso.HTTP_METHOD_SOAP:
return
return redirect(get_request().environ['SCRIPT_NAME'] + '/logout')
else:
if identity.lasso_dump:
# keep a copy of the identity dump, for singleLogoutReturn
session.lasso_identity_dump = identity.lasso_dump
session.store()
logout.setIdentityFromDump(identity.lasso_dump)
if method == lasso.HTTP_METHOD_SOAP:
return self.slo_idp_soap(logout)
else:
return self.slo_idp_get(logout)
def slo_idp_get [html] (self, logout, url = None):
# Single Logout initiated by IdP; GET profile
session = get_session()
session.in_slo_get = True
if not url:
url = '%s/logout' % get_request().environ['SCRIPT_NAME']
template.html_top(onload = "window.location = '%s'" % url)
'<div id="logout-top"><h1>%s</h1></div>' % _('Logout')
"""<div id="logout-sps">
<p>%s</p>
<ul>""" % _('Logging out from service providers:')
remote_provider_id = logout.getNextProviderId()
while remote_provider_id is not None:
try:
t = logout.initRequest(remote_provider_id, lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND:
get_logger().warn('SLO/GET failed: identity not found')
break
elif error[0] == lasso.LOGIN_ERROR_FEDERATION_NOT_FOUND:
'<li>%s... %s</li>' % (remote_provider_id, _('federation not found'))
elif error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
'<li>%s... %s</li>' % (remote_provider_id, _('logout not supported'))
else:
raise
else:
t = logout.buildRequestMsg()
session.lasso_logout_dump = logout.dump()
organization_name = logout.server.getProvider(remote_provider_id).getOrganization() or remote_provider_id
'<li>%s... <img src="%s" alt="" width="12" height="12" /></li>' % (
organization_name, logout.msgUrl)
remote_provider_id = logout.getNextProviderId()
'</ul></div>'
'<p><a href="%s">%s</a></p>' % (url, _('Finish logging out'))
def slo_idp_soap(self, logout):
remote_provider_id = logout.getNextProviderId()
session = get_session()
finish_with_get = False
while remote_provider_id:
try:
logout.initRequest(remote_provider_id, lasso.HTTP_METHOD_SOAP)
except lasso.ProfileIdentityNotFoundError:
# FIXME: this should not happen
get_logger().warn('SLO/SOAP initRequest failed error: IdentityNotFound')
break # this is bad, abort.
except lasso.ProfileUnsupportedProfileError:
# If one SP doesn't support SLO SOAP binding, switch to SLO GET
# binding for all SP
finish_with_get = True
except lasso.Error, error:
raise
else:
try:
logout.buildRequestMsg()
soap_answer = self.soap_call(logout.msgUrl, logout.msgBody)
except soap.SOAPException:
pass
except lasso.ServerProviderNotFoundError:
get_logger().warn('SLO/SOAP failed because provider was not found, providerID: %s' % remote_provider_id)
except lasso.ProfileUnknownProfileUrlError:
get_logger().warn('SLO/SOAP failed because profile URL was empty, providerID: %s' % remote_provider_id)
except lasso.ProfileMissingRequestError:
get_logger().warn('SLO/SOAP failed because of a missing request, providerID: %s' % remote_provider_id)
except lasso.Error, error:
get_logger().warn('SLO/SOAP buildRequestMsg error, providerID: %s error: %s' % (remote_provider_id, error[1]))
else:
try:
logout.processResponseMsg(soap_answer)
except lasso.ProfileInvalidMsgError:
get_logger().warn('SLO/SOAP response is invalid, providerID: %s' % remote_provider_id)
except lasso.ProfileStatusNotSuccessError:
get_logger().warn('SLO/SOAP response status is not success, providerID: %s status: %s' % (remote_provider_id, logout.response.status.statusCode.value))
except lasso.LogoutRequestDeniedError:
get_logger().warn('SLO/SOAP request denied, providerID: %s' % (remote_provider_id))
except lasso.Error, error:
get_logger().warn('SLO/SOAP error, providerID: %s error: %s' % (remote_provider_id, error[1]))
remote_provider_id = logout.getNextProviderId()
if finish_with_get:
logout.resetProviderIdIndex()
return self.slo_idp_get(logout)
else:
return redirect(get_request().environ['SCRIPT_NAME'] + '/logout')
def singleLogoutReturn(self):
session = get_session()
if (not session or not session.user or not session.lasso_session_dump) and not hasattr(session, "lasso_identity_dump"):
raise errors.AccessError()
logout = lasso.Logout.newFromDump(get_lasso_server(), session.lasso_logout_dump)
if not logout:
# strange thing, should not happen, but handle it nicely
response = get_response()
response.set_content_type("image/png")
return file(os.path.join(get_publisher().DATA_DIR, 'liberty/check_on.png')).read()
logout.setSessionFromDump(session.lasso_session_dump)
if hasattr(session, "lasso_identity_dump"):
# FIXME: in later version of lasso this should be useless
logout.setIdentityFromDump(session.lasso_identity_dump)
else:
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
pass
else:
logout.setIdentityFromDump(identity.lasso_dump)
request = get_request()
try:
logout.processResponseMsg(request.get_query())
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_INVALID_QUERY:
raise errors.AccessError()
raise
if logout.session is None:
session.lasso_session_dump = None
session.lasso_logout_dump = None # it was the last one.
else:
session.lasso_session_dump = logout.session.dump()
if session.in_slo_get:
return redirect(get_publisher().get_root_url() + 'images/check_on.png')
else:
return self.slo_sp_continue_with_http(logout, session)
def slo_sp(self):
"Single Logout initiated by service provider"
request = get_request()
logout = lasso.Logout(get_lasso_server())
try:
logout.processRequestMsg(request.get_query())
except lasso.Error, error:
if error[0] == lasso.DS_ERROR_INVALID_SIGNATURE:
return template.error_page(_('Failed to check single logout request signature.'))
raise
get_logger().info('SLO from %s' % logout.request.providerId)
session = get_session()
if not session.lasso_session_dump:
pass # session got closed by an other mean
elif logout.nameIdentifier.content not in (session.name_identifiers or []):
pass # same
else:
logout.setSessionFromDump(session.lasso_session_dump)
authentic.identities.get_store().load_identities()
identity = None
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
pass
else:
if identity.lasso_dump:
logout.setIdentityFromDump(identity.lasso_dump)
try:
logout.validateRequest()
except lasso.Error, error:
if error[0] != lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
raise
try:
logout.buildResponseMsg()
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_UNKNOWN_PROFILE_URL:
# metadata didn't contain logout return url, stay here.
return redirect(get_request().environ['SCRIPT_NAME'] + '/')
raise
return redirect(logout.msgUrl)
if logout.session is None:
session.lasso_session_dump = None
else:
session.lasso_session_dump = logout.session.dump()
method = lasso.HTTP_METHOD_SOAP
if method == lasso.HTTP_METHOD_SOAP:
remote_provider_id = logout.getNextProviderId()
while remote_provider_id:
try:
logout.initRequest(remote_provider_id, method)
except lasso.Error, error:
if error[0] in (lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE,
lasso.PROFILE_ERROR_FEDERATION_NOT_FOUND):
remote_provider_id = logout.getNextProviderId()
continue
else:
raise
logout.buildRequestMsg()
try:
soap_answer = self.soap_call(logout.msgUrl, logout.msgBody)
except soap.SOAPException:
remote_provider_id = logout.getNextProviderId()
continue
try:
logout.processResponseMsg(soap_answer)
except:
remote_provider_id = logout.getNextProviderId()
get_logger().warn('Invalid SOAP SLO answer from %s' % logout.msgUrl)
continue
nameIdentifier = logout.nameIdentifier.content
remote_provider_id = logout.getNextProviderId()
return self.slo_sp_continue_with_http(logout, session)
def slo_sp_continue_with_http(self, logout, session):
logout.resetProviderIdIndex()
while True: # to skip non-compliant providers
remote_provider_id = logout.getNextProviderId()
if remote_provider_id is None:
logout.buildResponseMsg()
if session.proxied_idp:
get_session().after_url = logout.msgUrl
return redirect(get_request().environ['SCRIPT_NAME'] + '/liberty/proxySingleLogout')
get_session_manager().expire_session()
return redirect(logout.msgUrl)
else:
try:
logout.initRequest(remote_provider_id, lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
if error[0] in (lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE,
lasso.PROFILE_ERROR_FEDERATION_NOT_FOUND):
# it doesn't support nor SOAP nor Redirect ?
# And it calls itself Liberty compliant ?
continue # ignore it.
raise
logout.buildRequestMsg()
session.lasso_logout_dump = logout.dump()
return redirect(logout.msgUrl)
def federationTermination(self):
request = get_request()
if not lasso.isLibertyQuery(request.get_query()):
return redirect('.')
defederation = lasso.Defederation(get_lasso_server())
defederation.processNotificationMsg(request.get_query())
session = get_session()
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
identity = None
return self.fedterm(defederation, identity, session)
def fedterm(self, defederation, identity, session):
if session and session.lasso_session_dump:
defederation.setSessionFromDump(session.lasso_session_dump)
if identity and identity.lasso_dump:
defederation.setIdentityFromDump(identity.lasso_dump)
get_logger().info('fedterm for %s from %s' % (identity.id, defederation.request.providerId))
else:
get_logger().info('fedterm from %s' % defederation.request.providerId)
try:
defederation.validateNotification()
except lasso.Error, error:
pass # ignore failure (?)
else:
if not defederation.identity:
# if it was the last federation the whole identity dump collapsed
identity.lasso_dump = None
else:
identity.lasso_dump = defederation.identity.dump()
authentic.identities.get_store().save(identity)
if session:
name_identifier = defederation.nameIdentifier.content
if name_identifier in (session.name_identifiers or []):
session.name_identifiers.remove(name_identifier)
if defederation.isSessionDirty:
if defederation.session:
session.lasso_session_dump = defederation.session.dump()
else:
session.lasso_session_dump = None
if defederation.msgUrl:
return redirect(defederation.msgUrl)
else:
get_session_manager().commit_changes(session)
response = get_response()
response.set_status(204)
return ''
def federationTerminationReturn(self):
return redirect('..')
def registerNameIdentifier(self):
request = get_request()
if not lasso.isLibertyQuery(request.get_query()):
return redirect('.')
registration = lasso.NameRegistration(get_lasso_server())
registration.processRequestMsg(request.get_query())
session = get_session()
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
identity = None
return self.rni(registration, identity, session)
def rni(self, registration, identity, session):
if session and session.lasso_session_dump:
registration.setSessionFromDump(session.lasso_session_dump)
if identity:
registration.setIdentityFromDump(identity.lasso_dump)
registration.validateRequest()
if registration.identity:
identity.lasso_dump = registration.identity.dump()
authentic.identities.get_store().save(identity)
registration.buildResponseMsg()
if registration.msgUrl:
return redirect(registration.msgUrl)
else:
get_session_manager().commit_changes(session)
return registration.msgBody
def perform_proxy_login(self, idp = None, nameIdPolicy = None, extensions = None, relay_state = None):
session = get_session()
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
login = lasso.Login(server)
login.initAuthnRequest(idp, lasso.HTTP_METHOD_REDIRECT)
login.request.nameIdPolicy = 'federated'
login.request.forceAuthn = False
login.request.isPassive = False
login.request.consent = "urn:liberty:consent:obtained"
if session.lasso_login_dump:
# replicates parameters from the request we proxy
orig_login = lasso.Login.newFromDump(get_lasso_server(), session.lasso_login_dump)
login.request.nameIdPolicy = orig_login.request.nameIdPolicy
login.request.forceAuthn = orig_login.request.forceAuthn
login.request.isPassive = orig_login.request.isPassive
login.request.consent = orig_login.request.consent
if nameIdPolicy: # forced value
login.request.nameIdPolicy = nameIdPolicy
if extensions:
ext_list = lasso.StringList()
for ext in extensions:
ext_list.append('<lib:Extension xmlns:lib="urn:liberty:iff:2003-08"><%s>%s</%s></lib:Extension>' % (ext[0], ext[1], ext[0]))
login.request.extension = ext_list
if relay_state is not None:
get_session().remember(login.request.iD, relay_state)
login.buildAuthnRequestMsg()
return redirect(login.msgUrl)
def proxy_auth_ok(self, login):
pass # to override
def proxy_auth_peer_cancelled(self, login):
pass
def proxy_auth_federation_not_found(self, login):
pass
def proxyAssertionConsumer(self):
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
login = lasso.Login(server)
request = get_request()
if request.get_method() == 'GET' or get_field('LAREQ'):
if request.get_method() == 'GET':
try:
login.initRequest(request.get_query(), lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
if hasattr(lasso, 'strError'):
return template.error_page(lasso.strError(error[0]))
return template.error_page(_('Liberty error (lasso code: %s)') % error[0])
else:
login.initRequest(get_field('LAREQ'), lasso.HTTP_METHOD_POST)
login.buildRequestMsg()
try:
soap_answer = self.soap_call(login.msgUrl, login.msgBody)
except soap.SOAPException:
return template.error_page(_('Failed to get Assertion from identity provider'))
try:
login.processResponseMsg(soap_answer)
except lasso.Error, error:
if error[0] == lasso.LOGIN_ERROR_FEDERATION_NOT_FOUND:
t = self.proxy_auth_federation_not_found(login)
if t:
return t
if error[0] != lasso.LOGIN_ERROR_UNKNOWN_PRINCIPAL:
raise
t = self.proxy_auth_peer_cancelled(login)
if t:
return t
session = get_session()
login = lasso.Login.newFromDump(get_lasso_server(), session.lasso_login_dump)
session.lasso_login_dump = None
return self.sso_after_authentication(login, False, proxied = True)
else:
self.proxy_auth_ok(login)
else:
login.processAuthnResponseMsg(get_field('LARES'))
session = get_session()
if session.lasso_proxy_session_dump:
login.setSessionFromDump(session.lasso_proxy_session_dump)
try:
common.SessionIndex(login.response.assertion[0].authenticationStatement.sessionIndex).store()
except:
pass
ni = login.nameIdentifier.content
authentic.identities.get_store().load_identities()
identity = authentic.identities.get_store().get_identity_for_name_identifier(ni)
if identity is None and get_session().user:
identity = authentic.identities.get_store().get_identity(get_session().user)
if identity:
if identity.lasso_proxy_dump:
login.setIdentityFromDump(identity.lasso_proxy_dump)
else:
# XXX: only create identity when "federated" ?
identity = authentic.identities.Identity()
identity_keys = authentic.identities.get_store().keys()
base_key = get_provider_key(login.remoteProviderId)
i = 1
while ('%s-%d' % (base_key, i)) in identity_keys:
i+=1
identity.id = '%s-%d' % (base_key, i)
identity.name = ''
identity.email = ''
identity.proxied_identity_origin = login.remoteProviderId
authentic.identities.get_store().add(identity)
session.set_user(identity.id)
session.authentication_instant = datetime.datetime.utcnow()
session.authentication_method = 'saml'
session.proxied_idp = login.remoteProviderId
if not session.name_identifiers:
session.name_identifiers = []
session.name_identifiers.append(login.nameIdentifier.content)
login.acceptSso()
if login.isIdentityDirty:
identity.lasso_proxy_dump = login.identity.dump()
if login.isSessionDirty:
session.lasso_proxy_session_dump = login.session.dump()
authentic.identities.get_store().save(identity)
if session.lasso_login_dump:
login = lasso.Login.newFromDump(get_lasso_server(), session.lasso_login_dump)
session.lasso_login_dump = None
return self.sso_after_authentication(login, True, proxied = True)
if session.after_url:
after_url = session.after_url
session.after_url = None
return redirect(after_url)
return redirect(get_request().environ['SCRIPT_NAME'] + '/')
@common.soap_endpoint
def proxySoapEndpoint(self):
"""handles SOAP message coming from an IdP we act as proxy for"""
soap_message = self.get_soap_message()
request_type = lasso.getRequestTypeFromSoapMsg(soap_message)
if request_type == lasso.REQUEST_TYPE_LOGOUT:
return self.proxy_soap_logout(soap_message)
if request_type == lasso.REQUEST_TYPE_DEFEDERATION:
return self.proxy_soap_fedterm(soap_message)
def proxy_soap_logout(self, soap_message):
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
logout = lasso.Logout(server)
logout.processRequestMsg(soap_message)
name_identifier = logout.nameIdentifier.content
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity_for_name_identifier(name_identifier)
if identity and identity.lasso_proxy_dump:
logout.setIdentityFromDump(identity.lasso_proxy_dump)
if logout.request.sessionIndex:
session_index = common.SessionIndex.get(logout.request.sessionIndex)
sessions = [ get_session_manager().get(session_index.session_id) ]
else:
sessions = authentic.sessions.BasicSession.get_sessions_by_user(identity.id)
except KeyError:
# no session, build straight failure answer
logout.buildResponseMsg()
return logout.msgBody
try:
logout.validateRequest()
except lasso.DsSignatureError:
pass
else:
for session in sessions:
self.slo_idp(session, method = lasso.HTTP_METHOD_SOAP)
session_manager = get_session_manager()
del session_manager[session.id]
logout.buildResponseMsg()
return logout.msgBody
def proxy_soap_fedterm(self, soap_message):
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
defederation = lasso.Defederation(server)
defederation.processNotificationMsg(soap_message)
name_identifier = defederation.nameIdentifier.content
try:
identity = authentic.identities.get_store().get_identity_for_name_identifier(name_identifier)
except KeyError:
identity = None # XXX: should not happen
for session in get_session_manager().values():
if name_identifier in (session.name_identifiers or []):
get_logger().info('FedTerm/SOAP/Proxy from %s' % defederation.remoteProviderId)
defederation.setSessionFromDump(session.lasso_proxy_session_dump)
break
else:
pass
if identity and identity.lasso_proxy_dump:
defederation.setIdentityFromDump(identity.lasso_proxy_dump)
try:
defederation.validateNotification()
except lasso.Error, error:
pass # ignore failure (?)
else:
if not defederation.identity:
# if it was the last federation the whole identity dump collapsed
identity.lasso_proxy_dump = None
else:
identity.lasso_proxy_dump = defederation.identity.dump()
authentic.identities.get_store().save(identity)
if defederation.isSessionDirty:
if session:
name_identifier = defederation.nameIdentifier.content
if name_identifier in (session.name_identifiers or []):
session.name_identifiers.remove(name_identifier)
if defederation.session:
session.lasso_proxy_session_dump = defederation.session.dump()
else:
session.lasso_proxy_session_dump = None
# and now, fedterm with SP, every SP.
server = get_lasso_server()
if identity and identity.lasso_dump:
lasso_identity = lasso.Identity.newFromDump(identity.lasso_dump)
provider_ids = lasso_identity.providerIds or []
else:
provider_ids = []
for k in provider_ids:
provider = server.getProvider(k)
if not provider:
continue
defederation = lasso.Defederation(server)
if identity.lasso_dump:
defederation.setIdentityFromDump(identity.lasso_dump)
if session.lasso_session_dump:
defederation.setSessionFromDump(session.lasso_session_dump)
try:
defederation.initNotification(provider.providerId, lasso.HTTP_METHOD_SOAP)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_FEDERATION_NOT_FOUND:
raise
elif error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
continue # shit, ignore for now.
else:
raise
defederation.buildNotificationMsg()
if not defederation.identity:
identity.lasso_dump = None
else:
identity.lasso_dump = defederation.identity.dump()
if session:
if not defederation.session:
session.lasso_session_dump = None
else:
session.lasso_session_dump = defederation.session.dump()
name_identifier = defederation.nameIdentifier.content
if name_identifier in (session.name_identifiers or []):
session.name_identifiers.remove(name_identifier)
try:
self.soap_call(defederation.msgUrl, defederation.msgBody)
except soap.SOAPException:
pass
authentic.identities.get_store().save(identity)
get_session_manager().commit_changes(session)
response = get_response()
response.set_status(204)
return ''
def proxySingleLogout(self, session = None):
request = get_request()
if not lasso.isLibertyQuery(request.get_query()):
if not session:
session = get_session()
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
logout = lasso.Logout(server)
if session and session.lasso_proxy_session_dump:
logout.setSessionFromDump(session.lasso_proxy_session_dump)
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
pass
else:
if identity.lasso_proxy_dump:
logout.setIdentityFromDump(identity.lasso_proxy_dump)
try:
logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
session.lasso_proxy_session_dump = None
if error[0] == lasso.PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND:
return redirect('/logout')
if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
return redirect('/logout')
raise
logout.buildRequestMsg()
return redirect(logout.msgUrl)
else:
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
logout = lasso.Logout(server)
logout.processRequestMsg(request.get_query())
return self.proxy_slo_redirect(logout, get_session())
def proxySingleLogoutReturn(self):
session = get_session()
session.lasso_proxy_session_dump = None
get_session_manager().expire_session()
if session.after_url:
after_url = session.after_url
session.after_url = None
return redirect(after_url)
return redirect(get_request().environ['SCRIPT_NAME'] + '/logout')
def proxy_slo_soap(self, session, identity):
# slo request from SP, continue with SOAP logout request to proxied-IdP
server = authentic.misc.get_lasso_server(lasso.PROVIDER_ROLE_SP)
logout = lasso.Logout(server)
if session and session.lasso_proxy_session_dump:
logout.setSessionFromDump(session.lasso_proxy_session_dump)
if identity and identity.lasso_proxy_dump:
logout.setIdentityFromDump(identity.lasso_proxy_dump)
logout.initRequest(session.proxied_idp, lasso.HTTP_METHOD_SOAP)
logout.buildRequestMsg()
try:
soap_answer = self.soap_call(logout.msgUrl, logout.msgBody)
except soap.SOAPException:
return # ignore
try:
logout.processResponseMsg(soap_answer)
except lasso.Error, error:
if error[0] not in (lasso.LOGOUT_ERROR_UNSUPPORTED_PROFILE,
lasso.LOGOUT_ERROR_FEDERATION_NOT_FOUND):
raise
# XXX: it should actually answer back
pass
if logout.isSessionDirty:
if logout.session:
session.lasso_proxy_session_dump = logout.session.dump()
else:
session.lasso_proxy_session_dump = ''
get_session_manager().commit_changes(session)
def proxy_slo_redirect(self, logout, session):
logout_idp = lasso.Logout(get_lasso_server())
if session:
if session.lasso_proxy_session_dump:
logout.setSessionFromDump(session.lasso_proxy_session_dump)
if session.lasso_session_dump:
logout_idp.setSessionFromDump(session.lasso_session_dump)
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
pass
else:
if identity.lasso_proxy_dump:
logout.setIdentityFromDump(identity.lasso_proxy_dump)
if identity.lasso_dump:
logout_idp.setIdentityFromDump(identity.lasso_dump)
try:
logout.validateRequest()
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_SESSION_NOT_FOUND:
pass
elif error[0] < 0:
raise
pass
logout.buildResponseMsg()
session.after_url = logout.msgUrl
return self.slo_idp_get(logout_idp, url = 'proxySingleLogoutNext')
def proxySingleLogoutNext(self):
url = get_session().after_url
get_session_manager().expire_session()
return redirect(url)
def metadata(self):
get_publisher().reload_cfg()
response = get_response()
response.set_content_type('text/xml', 'utf-8')
metadata = unicode(open(authentic.misc.get_abs_path(
get_cfg('idp')['metadata'])).read(), 'utf-8')
return metadata
def public_key(self):
get_publisher().reload_cfg()
response = get_response()
response.set_content_type('application/octet-stream')
publickey = file(authentic.misc.get_abs_path(get_cfg('idp')['publickey'])).read()
return publickey
class SpUI(AccessControlled, Directory):
_q_exports = ['terminate', 'login', 'proxy_terminate']
def _q_access(self):
session = get_session()
if not session or session.user is None:
raise errors.AccessUnauthorizedError()
def __init__(self, component):
self.provider_key = component
def init_provider(self, role = lasso.PROVIDER_ROLE_SP):
try:
lp = get_cfg('providers')[self.provider_key]
except KeyError:
raise errors.TraversalError()
if lp['role'] != role and lp['role'] != lasso.PROVIDER_ROLE_NONE:
raise errors.TraversalError()
self.p = lasso.Provider(role,
authentic.misc.get_abs_path(lp['metadata']),
authentic.misc.get_abs_path(lp.get('publickey')), None)
def login(self, relay_state=None):
self.init_provider()
login = lasso.Login(get_lasso_server())
login.initIdpInitiatedAuthnRequest(self.p.providerId)
if relay_state:
login.msgRelayState = relay_state
get_logger().info('SSO to %s' % self.p.providerId)
login.request.protocolProfile = lasso.LIB_PROTOCOL_PROFILE_BRWS_ART
login.processAuthnRequestMsg(None)
rt = RootDirectory()
return rt.sso_after_consent(login, True, True)
def terminate(self):
self.init_provider()
defederation = lasso.Defederation(get_lasso_server())
session = get_session()
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
identity = None
if identity and identity.lasso_dump:
defederation.setIdentityFromDump(identity.lasso_dump)
if session and session.lasso_session_dump:
defederation.setSessionFromDump(session.lasso_session_dump)
get_logger().info('fedterm to %s' % self.p.providerId)
try:
defederation.initNotification(self.p.providerId, lasso.HTTP_METHOD_SOAP)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_FEDERATION_NOT_FOUND:
raise errors.TraversalError() # no such federation
if error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND:
raise errors.TraversalError() # no such federation
elif error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
try:
defederation.initNotification(self.p.providerId, lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
# XXX: perhaps it could remove the federation locally,
# ignoring the remote provider?
return template.error_page(
_("This service doesn't support federation termination"))
raise
else:
raise
defederation.buildNotificationMsg()
name_identifier = defederation.nameIdentifier.content
if not defederation.identity:
# if it was the last federation the whole identity dump collapsed
identity.lasso_dump = None
else:
identity.lasso_dump = defederation.identity.dump()
authentic.identities.get_store().save(identity)
if name_identifier in (session.name_identifiers or []):
session.name_identifiers.remove(name_identifier)
if defederation.msgBody:
try:
self.soap_call(defederation.msgUrl, defederation.msgBody)
except soap.SOAPException:
return template.error_page(_("Service provider failed to process request."))
else:
return redirect(defederation.msgUrl)
return redirect('../../..')
def proxy_terminate(self):
self.init_provider(lasso.PROVIDER_ROLE_IDP)
defederation = lasso.Defederation(get_lasso_server(lasso.PROVIDER_ROLE_SP))
session = get_session()
authentic.identities.get_store().load_identities()
try:
identity = authentic.identities.get_store().get_identity(session.user)
except KeyError:
identity = None
if identity and identity.lasso_proxy_dump:
defederation.setIdentityFromDump(identity.lasso_proxy_dump)
if session and session.lasso_session_dump:
defederation.setSessionFromDump(session.lasso_session_dump)
get_logger().info('fedterm to %s' % self.p.providerId)
try:
defederation.initNotification(self.p.providerId, lasso.HTTP_METHOD_SOAP)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_FEDERATION_NOT_FOUND:
raise errors.TraversalError() # no such federation
if error[0] == lasso.PROFILE_ERROR_IDENTITY_NOT_FOUND:
raise errors.TraversalError() # no such federation
elif error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
try:
defederation.initNotification(self.p.providerId, lasso.HTTP_METHOD_REDIRECT)
except lasso.Error, error:
if error[0] == lasso.PROFILE_ERROR_UNSUPPORTED_PROFILE:
# XXX: perhaps it could remove the federation locally,
# ignoring the remote provider?
return template.error_page(
_("This service doesn't support federation termination"))
raise
else:
raise
defederation.buildNotificationMsg()
name_identifier = defederation.nameIdentifier.content
if not defederation.identity:
# if it was the last federation the whole identity dump collapsed
identity.lasso_proxy_dump = None
else:
identity.lasso_proxy_dump = defederation.identity.dump()
authentic.identities.get_store().save(identity)
if name_identifier in (session.name_identifiers or []):
session.name_identifiers.remove(name_identifier)
if defederation.msgBody:
try:
self.soap_call(defederation.msgUrl, defederation.msgBody)
except soap.SOAPException:
return template.error_page(_('Remote identity provider failed to process request.'))
else:
return redirect(defederation.msgUrl)
return redirect('../../..')