996 lines
51 KiB
Python
996 lines
51 KiB
Python
#! /usr/bin/env python
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
|
|
# PyLasso -- Python bindings for Lasso library
|
|
#
|
|
# Copyright (C) 2004 Entr'ouvert
|
|
# http://lasso.entrouvert.org
|
|
#
|
|
# Authors: Nicolas Clapies <nclapies@entrouvert.com>
|
|
# Valery Febvre <vfebvre@easter-eggs.com>
|
|
# Emmanuel Raviart <eraviart@entrouvert.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
import unittest
|
|
import sys
|
|
|
|
sys.path.insert(0, '..')
|
|
sys.path.insert(0, '../.libs')
|
|
|
|
|
|
import lasso
|
|
|
|
|
|
# FIXME: Replace principal with client in most methods.
|
|
# FIXME: Rename webUser to userAccount.
|
|
|
|
|
|
class HttpRequest(object):
|
|
client = None # Principal or web site sending the request.
|
|
body = None
|
|
header = None
|
|
method = None # "GET" or "POST" or "PUT" or...
|
|
url = None
|
|
|
|
def __init__(self, client, method, url, body = None):
|
|
self.client = client
|
|
self.method = method
|
|
self.url = url
|
|
if body:
|
|
self.body = body
|
|
|
|
def ask(self):
|
|
webSite = self.client.internet.getWebSite(self.url)
|
|
return webSite.doHttpRequest(self)
|
|
|
|
|
|
class HttpResponse(object):
|
|
body = None
|
|
header = None
|
|
statusCode = None # 200 or...
|
|
statusMessage = None
|
|
|
|
def __init__(self, statusCode, statusMessage = None, body = None):
|
|
self.statusCode = statusCode
|
|
if statusMessage:
|
|
self.statusMessage = statusMessage
|
|
if body:
|
|
self.body = body
|
|
|
|
|
|
class Internet(object):
|
|
webSites = None
|
|
|
|
def __init__(self):
|
|
self.webSites = {}
|
|
|
|
def addWebSite(self, webSite):
|
|
self.webSites[webSite.url] = webSite
|
|
|
|
def getWebSite(self, url):
|
|
for webSiteUrl, webSite in self.webSites.iteritems():
|
|
if url.startswith(webSiteUrl):
|
|
return webSite
|
|
raise Exception("Unknown web site: %s" % url)
|
|
|
|
|
|
class WebClient(object):
|
|
internet = None
|
|
keyring = None
|
|
webSessionIds = None # Simulate the cookies, stored in user's navigator, and containing the
|
|
# IDs of sessions already opened by the user.
|
|
|
|
def __init__(self, internet):
|
|
self.internet = internet
|
|
self.keyring = {}
|
|
self.webSessionIds = {}
|
|
|
|
def redirect(self, url):
|
|
webSite = self.internet.getWebSite(url)
|
|
return webSite.doHttpRequest(HttpRequest(self, "GET", url))
|
|
|
|
|
|
class Principal(WebClient):
|
|
"""Simulation of a user and its web navigator"""
|
|
|
|
name = None # The user name
|
|
|
|
def __init__(self, internet, name):
|
|
WebClient.__init__(self, internet)
|
|
self.name = name
|
|
|
|
|
|
class Simulation(object):
|
|
test = None # The testing instance
|
|
|
|
def __init__(self, test):
|
|
self.test = test
|
|
|
|
def fail(self, msg = None):
|
|
return self.test.fail(msg)
|
|
|
|
def failIf(self, expr, msg = None):
|
|
return self.test.failIf(expr, msg)
|
|
|
|
def failIfAlmostEqual(self, first, second, places = 7, msg = None):
|
|
return self.test.failIfAlmostEqual(first, second, places, msg)
|
|
|
|
def failIfEqual(self, first, second, msg = None):
|
|
return self.test.failIfEqual(first, second, msg)
|
|
|
|
def failUnless(self, expr, msg = None):
|
|
return self.test.failUnless(expr, msg)
|
|
|
|
def failUnlessAlmostEqual(self, first, second, places = 7, msg = None):
|
|
return self.test.failUnlessAlmostEqual(first, second, places, msg)
|
|
|
|
def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
|
|
return self.test.failUnlessRaises(self, excClass, callableObj, *args, **kwargs)
|
|
|
|
def failUnlessEqual(self, first, second, msg = None):
|
|
return self.test.failUnlessEqual(first, second, msg)
|
|
|
|
|
|
class WebSession(object):
|
|
"""Simulation of session of a web site"""
|
|
|
|
expirationTime = None # A sample session variable
|
|
loginDump = None # Used only by some identity providers
|
|
uniqueId = None # The session number
|
|
sessionDump = None
|
|
webUserId = None # ID of logged user.
|
|
|
|
def __init__(self, uniqueId):
|
|
self.uniqueId = uniqueId
|
|
|
|
|
|
class WebUser(object):
|
|
"""Simulation of user of a web site"""
|
|
|
|
identityDump = None
|
|
language = 'fr' # A sample user variable
|
|
uniqueId = None # The user name is used as an ID in this simulation.
|
|
|
|
def __init__(self, uniqueId):
|
|
self.uniqueId = uniqueId
|
|
|
|
|
|
class WebSite(WebClient, Simulation):
|
|
"""Simulation of a web site"""
|
|
|
|
lastWebSessionId = 0
|
|
providerId = None # The Liberty providerID of this web site
|
|
serverDump = None
|
|
url = None # The main URL of web site
|
|
webUserIdsByNameIdentifier = None
|
|
webUsers = None
|
|
webSessionIdsByNameIdentifier = None
|
|
webSessions = None
|
|
|
|
def __init__(self, test, internet, url):
|
|
Simulation.__init__(self, test)
|
|
WebClient.__init__(self, internet)
|
|
self.url = url
|
|
self.webUserIdsByNameIdentifier = {}
|
|
self.webUsers = {}
|
|
self.webSessionIdsByNameIdentifier = {}
|
|
self.webSessions = {}
|
|
self.internet.addWebSite(self)
|
|
|
|
def addWebUser(self, name):
|
|
self.webUsers[name] = WebUser(name)
|
|
|
|
def createWebSession(self, client):
|
|
self.lastWebSessionId += 1
|
|
webSession = WebSession(self.lastWebSessionId)
|
|
self.webSessions[self.lastWebSessionId] = webSession
|
|
client.webSessionIds[self.url] = self.lastWebSessionId
|
|
return webSession
|
|
|
|
def doHttpRequest(self, httpRequest):
|
|
url = httpRequest.url
|
|
if url.startswith(self.url):
|
|
url = url[len(self.url):]
|
|
methodName = url.split("?", 1)[0].replace("/", "")
|
|
method = getattr(self, methodName)
|
|
return method(httpRequest)
|
|
|
|
def extractQueryFromUrl(self, url):
|
|
return url.split("?", 1)[1]
|
|
|
|
def getIdentityDump(self, principal):
|
|
webSession = self.getWebSession(principal)
|
|
webUser = self.getWebUserFromWebSession(webSession)
|
|
if webUser is None:
|
|
return None
|
|
return webUser.identityDump
|
|
|
|
def getServer(self):
|
|
return lasso.Server.new_from_dump(self.serverDump)
|
|
|
|
def getSessionDump(self, principal):
|
|
webSession = self.getWebSession(principal)
|
|
if webSession is None:
|
|
return None
|
|
return webSession.sessionDump
|
|
|
|
def getWebSession(self, principal):
|
|
webSessionId = principal.webSessionIds.get(self.url, None)
|
|
if webSessionId is None:
|
|
# The user has no web session opened on this site.
|
|
return None
|
|
return self.webSessions.get(webSessionId, None)
|
|
|
|
def getWebSessionFromNameIdentifier(self, nameIdentifier):
|
|
webSessionId = self.webSessionIdsByNameIdentifier.get(nameIdentifier, None)
|
|
if webSessionId is None:
|
|
# The user has no federation on this site or has no authentication assertion for this
|
|
# federation.
|
|
return None
|
|
return self.webSessions.get(webSessionId, None)
|
|
|
|
def getWebUserFromNameIdentifier(self, nameIdentifier):
|
|
webUserId = self.webUserIdsByNameIdentifier.get(nameIdentifier, None)
|
|
if webUserId is None:
|
|
# The user has no federation on this site.
|
|
return None
|
|
return self.webUsers.get(webUserId, None)
|
|
|
|
def getWebUserFromWebSession(self, webSession):
|
|
if webSession is None:
|
|
return None
|
|
webUserId = webSession.webUserId
|
|
if webUserId is None:
|
|
# The user has no account on this site.
|
|
return None
|
|
return self.webUsers.get(webUserId, None)
|
|
|
|
|
|
class IdpSite(WebSite):
|
|
soapResponseMsgs = None
|
|
|
|
def __init__(self, test, internet, url):
|
|
WebSite.__init__(self, test, internet, url)
|
|
self.soapResponseMsgs = {}
|
|
|
|
def singleSignOn(self, httpRequest):
|
|
server = self.getServer()
|
|
login = lasso.Login.new(server)
|
|
identityDump = self.getIdentityDump(httpRequest.client)
|
|
if identityDump is not None:
|
|
login.set_identity_from_dump(identityDump)
|
|
sessionDump = self.getSessionDump(httpRequest.client)
|
|
if sessionDump is not None:
|
|
login.set_session_from_dump(sessionDump)
|
|
authnRequestQuery = self.extractQueryFromUrl(httpRequest.url)
|
|
login.init_from_authn_request_msg(authnRequestQuery, lasso.httpMethodRedirect)
|
|
|
|
self.failUnless(login.must_authenticate()) # FIXME: To improve.
|
|
webSession = self.getWebSession(httpRequest.client)
|
|
if webSession is None:
|
|
webSession = self.createWebSession(httpRequest.client)
|
|
webSession.loginDump = login.dump()
|
|
|
|
# A real identity provider using a HTML form to ask user's login & password would store
|
|
# idpLoginDump in a session variable and display the HTML login form.
|
|
webUserId = httpRequest.client.keyring.get(self.url, None)
|
|
userAuthenticated = webUserId in self.webUsers
|
|
if userAuthenticated:
|
|
webSession.webUserId = webUserId
|
|
authenticationMethod = lasso.samlAuthenticationMethodPassword # FIXME
|
|
|
|
server = self.getServer()
|
|
webSession = self.getWebSession(httpRequest.client)
|
|
loginDump = webSession.loginDump
|
|
del webSession.loginDump
|
|
login = lasso.Login.new_from_dump(server, loginDump)
|
|
# Set identity & session in login, because loginDump doesn't contain them.
|
|
identityDump = self.getIdentityDump(httpRequest.client)
|
|
if identityDump is not None:
|
|
login.set_identity_from_dump(identityDump)
|
|
sessionDump = self.getSessionDump(httpRequest.client)
|
|
if sessionDump is not None:
|
|
login.set_session_from_dump(sessionDump)
|
|
self.failUnlessEqual(login.protocolProfile, lasso.loginProtocolProfileBrwsArt) # FIXME
|
|
login.build_artifact_msg(
|
|
userAuthenticated, authenticationMethod, "FIXME: reauthenticateOnOrAfter",
|
|
lasso.httpMethodRedirect)
|
|
webUser = self.getWebUserFromWebSession(webSession)
|
|
if login.is_identity_dirty():
|
|
identityDump = login.get_identity().dump()
|
|
self.failUnless(identityDump)
|
|
webUser.identityDump = identityDump
|
|
self.failUnless(login.is_session_dirty())
|
|
sessionDump = login.get_session().dump()
|
|
self.failUnless(sessionDump)
|
|
webSession.sessionDump = sessionDump
|
|
nameIdentifier = login.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
self.webUserIdsByNameIdentifier[nameIdentifier] = webUser.uniqueId
|
|
self.webSessionIdsByNameIdentifier[nameIdentifier] = webSession.uniqueId
|
|
artifact = login.assertionArtifact
|
|
self.failUnless(artifact)
|
|
soapResponseMsg = login.response_dump
|
|
self.failUnless(soapResponseMsg)
|
|
self.soapResponseMsgs[artifact] = soapResponseMsg
|
|
responseUrl = login.msg_url
|
|
self.failUnless(responseUrl)
|
|
return httpRequest.client.redirect(responseUrl)
|
|
|
|
def soapEndpoint(self, httpRequest):
|
|
soapRequestMsg = httpRequest.body
|
|
requestType = lasso.get_request_type_from_soap_msg(soapRequestMsg)
|
|
if requestType == lasso.requestTypeLogin:
|
|
server = self.getServer()
|
|
login = lasso.Login.new(server)
|
|
login.process_request_msg(soapRequestMsg)
|
|
artifact = login.assertionArtifact
|
|
self.failUnless(artifact)
|
|
soapResponseMsg = self.soapResponseMsgs.get(artifact, None)
|
|
if soapResponseMsg is None:
|
|
raise Exception("FIXME: Handle the case when artifact is wrong")
|
|
return HttpResponse(200, body = soapResponseMsg)
|
|
elif requestType == lasso.requestTypeLogout:
|
|
server = self.getServer()
|
|
logout = lasso.Logout.new(server, lasso.providerTypeIdp)
|
|
logout.process_request_msg(soapRequestMsg, lasso.httpMethodSoap)
|
|
nameIdentifier = logout.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
|
|
# Retrieve session dump and identity dump using name identifier.
|
|
webSession = self.getWebSessionFromNameIdentifier(nameIdentifier)
|
|
if webSession is None:
|
|
raise Exception("FIXME: Handle the case when there is no web session")
|
|
sessionDump = webSession.sessionDump
|
|
if sessionDump is None:
|
|
raise Exception(
|
|
"FIXME: Handle the case when there is no session dump in web session")
|
|
logout.set_session_from_dump(sessionDump)
|
|
webUser = self.getWebUserFromNameIdentifier(nameIdentifier)
|
|
if webUser is None:
|
|
raise Exception("FIXME: Handle the case when there is no web user")
|
|
identityDump = webUser.identityDump
|
|
if identityDump is None:
|
|
raise Exception(
|
|
"FIXME: Handle the case when there is no identity dump in web user")
|
|
logout.set_identity_from_dump(identityDump)
|
|
|
|
logout.validate_request()
|
|
self.failIf(logout.is_identity_dirty())
|
|
identity = logout.get_identity()
|
|
self.failUnless(identity)
|
|
identityDump = identity.dump()
|
|
self.failUnless(identityDump)
|
|
self.failUnless(logout.is_session_dirty())
|
|
session = logout.get_session()
|
|
if session is None:
|
|
del webSession.sessionDump
|
|
else:
|
|
sessionDump = session.dump()
|
|
self.failUnless(sessionDump)
|
|
webSession.sessionDump = sessionDump
|
|
nameIdentifier = logout.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
del self.webSessionIdsByNameIdentifier[nameIdentifier]
|
|
|
|
# Tell each other service provider to logout the user.
|
|
otherProviderId = logout.get_next_providerID()
|
|
while otherProviderId is not None:
|
|
logout.init_request(otherProviderId)
|
|
logout.build_request_msg()
|
|
|
|
soapEndpoint = logout.msg_url
|
|
self.failUnless(soapEndpoint)
|
|
soapRequestMsg = logout.msg_body
|
|
self.failUnless(soapRequestMsg)
|
|
httpResponse = HttpRequest(self, "POST", soapEndpoint, body = soapRequestMsg).ask()
|
|
self.failUnlessEqual(httpResponse.statusCode, 200)
|
|
logout.process_response_msg(httpResponse.body, lasso.httpMethodSoap)
|
|
|
|
otherProviderId = logout.get_next_providerID()
|
|
|
|
logout.build_response_msg()
|
|
soapResponseMsg = logout.msg_body
|
|
self.failUnless(soapResponseMsg)
|
|
return HttpResponse(200, body = soapResponseMsg)
|
|
else:
|
|
raise Exception("Unknown request type: %s" % requestType)
|
|
|
|
|
|
class SpSite(WebSite):
|
|
idpSite = None # The identity provider, this service provider will use to authenticate users.
|
|
|
|
def assertionConsumer(self, httpRequest):
|
|
server = self.getServer()
|
|
login = lasso.Login.new(server)
|
|
responseQuery = self.extractQueryFromUrl(httpRequest.url)
|
|
login.init_request(responseQuery, lasso.httpMethodRedirect)
|
|
login.build_request_msg()
|
|
|
|
soapEndpoint = login.msg_url
|
|
self.failUnless(soapEndpoint)
|
|
soapRequestMsg = login.msg_body
|
|
self.failUnless(soapRequestMsg)
|
|
httpResponse = HttpRequest(self, "POST", soapEndpoint, body = soapRequestMsg).ask()
|
|
self.failUnlessEqual(httpResponse.statusCode, 200)
|
|
login.process_response_msg(httpResponse.body)
|
|
nameIdentifier = login.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
|
|
# Retrieve session dump, using name identifier or else try to use the client web session.
|
|
# If session dump exists, give it to Lasso, so that it updates it.
|
|
webSession = self.getWebSessionFromNameIdentifier(nameIdentifier)
|
|
if webSession is None:
|
|
webSession = self.getWebSession(httpRequest.client)
|
|
if webSession is not None:
|
|
sessionDump = webSession.sessionDump
|
|
if sessionDump is not None:
|
|
login.set_session_from_dump(sessionDump)
|
|
# Retrieve identity dump, using name identifier or else try to retrieve him from web
|
|
# session. If identity dump exists, give it to Lasso, so that it updates it.
|
|
webUser = self.getWebUserFromNameIdentifier(nameIdentifier)
|
|
if webUser is None:
|
|
webUser = self.getWebUserFromWebSession(webSession)
|
|
if webUser is not None:
|
|
identityDump = webUser.identityDump
|
|
if identityDump is not None:
|
|
login.set_identity_from_dump(sessionDump)
|
|
|
|
login.accept_sso()
|
|
if webUser is not None and identityDump is None:
|
|
self.failUnless(login.is_identity_dirty())
|
|
identity = login.get_identity()
|
|
self.failUnless(identity)
|
|
identityDump = identity.dump()
|
|
self.failUnless(identityDump)
|
|
self.failUnless(login.is_session_dirty())
|
|
session = login.get_session()
|
|
self.failUnless(session)
|
|
sessionDump = session.dump()
|
|
self.failUnless(sessionDump)
|
|
nameIdentifier = login.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
|
|
# User is now authenticated.
|
|
|
|
# If there was no web session yet, create it. Idem for the web user account.
|
|
if webSession is None:
|
|
webSession = self.createWebSession(httpRequest.client)
|
|
if webUser is None:
|
|
# A real service provider would ask user to login locally to create federation. Or it
|
|
# would ask user informations to create a local account.
|
|
webUserId = httpRequest.client.keyring.get(self.url, None)
|
|
userAuthenticated = webUserId in self.webUsers
|
|
if not userAuthenticated:
|
|
return HttpResponse(401, "Access Unauthorized: User has no account.")
|
|
webSession.webUserId = webUserId
|
|
webUser = self.webUsers[webUserId]
|
|
|
|
# Store the updated identity dump and session dump.
|
|
if login.is_identity_dirty():
|
|
webUser.identityDump = identityDump
|
|
webSession.sessionDump = sessionDump
|
|
self.webUserIdsByNameIdentifier[nameIdentifier] = webUser.uniqueId
|
|
self.webSessionIdsByNameIdentifier[nameIdentifier] = webSession.uniqueId
|
|
|
|
return HttpResponse(200)
|
|
|
|
def loginUsingRedirect(self, httpRequest):
|
|
server = self.getServer()
|
|
login = lasso.Login.new(server)
|
|
login.init_authn_request(self.idpSite.providerId)
|
|
self.failUnlessEqual(login.request_type, lasso.messageTypeAuthnRequest)
|
|
login.request.set_isPassive(False)
|
|
login.request.set_nameIDPolicy(lasso.libNameIDPolicyTypeFederated)
|
|
login.request.set_consent(lasso.libConsentObtained)
|
|
relayState = "fake"
|
|
login.request.set_relayState(relayState)
|
|
login.build_authn_request_msg()
|
|
authnRequestUrl = login.msg_url
|
|
self.failUnless(authnRequestUrl)
|
|
return httpRequest.client.redirect(authnRequestUrl)
|
|
|
|
def logoutUsingSoap(self, httpRequest):
|
|
webSession = self.getWebSession(httpRequest.client)
|
|
if webSession is None:
|
|
return HttpResponse(401, "Access Unauthorized: User has no session opened.")
|
|
webUser = self.getWebUserFromWebSession(webSession)
|
|
if webUser is None:
|
|
return HttpResponse(401, "Access Unauthorized: User is not logged in.")
|
|
|
|
server = self.getServer()
|
|
logout = lasso.Logout.new(server, lasso.providerTypeSp)
|
|
identityDump = self.getIdentityDump(httpRequest.client)
|
|
if identityDump is not None:
|
|
logout.set_identity_from_dump(identityDump)
|
|
sessionDump = self.getSessionDump(httpRequest.client)
|
|
if sessionDump is not None:
|
|
logout.set_session_from_dump(sessionDump)
|
|
logout.init_request()
|
|
logout.build_request_msg()
|
|
|
|
soapEndpoint = logout.msg_url
|
|
self.failUnless(soapEndpoint)
|
|
soapRequestMsg = logout.msg_body
|
|
self.failUnless(soapRequestMsg)
|
|
httpResponse = HttpRequest(self, "POST", soapEndpoint, body = soapRequestMsg).ask()
|
|
self.failUnlessEqual(httpResponse.statusCode, 200)
|
|
|
|
logout.process_response_msg(httpResponse.body, lasso.httpMethodSoap)
|
|
self.failIf(logout.is_identity_dirty())
|
|
identity = logout.get_identity()
|
|
self.failUnless(identity)
|
|
identityDump = identity.dump()
|
|
self.failUnless(identityDump)
|
|
self.failUnless(logout.is_session_dirty())
|
|
session = logout.get_session()
|
|
if session is None:
|
|
del webSession.sessionDump
|
|
else:
|
|
sessionDump = session.dump()
|
|
self.failUnless(sessionDump)
|
|
webSession.sessionDump = sessionDump
|
|
nameIdentifier = logout.nameIdentifier
|
|
self.failUnless(nameIdentifier)
|
|
del self.webSessionIdsByNameIdentifier[nameIdentifier]
|
|
|
|
return HttpResponse(200)
|
|
|
|
|
|
class TestCase(unittest.TestCase):
|
|
def generateIdpSite(self, internet):
|
|
site = IdpSite(self, internet, "https://identity-provider/")
|
|
site.providerId = "https://identity-provider/metadata"
|
|
|
|
server = lasso.Server.new(
|
|
"../../examples/data/idp-metadata.xml",
|
|
"../../examples/data/idp-public-key.pem",
|
|
"../../examples/data/idp-private-key.pem",
|
|
"../../examples/data/idp-crt.pem",
|
|
lasso.signatureMethodRsaSha1)
|
|
server.add_provider(
|
|
"../../examples/data/sp-metadata.xml",
|
|
"../../examples/data/sp-public-key.pem",
|
|
"../../examples/data/ca-crt.pem")
|
|
site.serverDump = server.dump()
|
|
self.failUnless(site.serverDump)
|
|
server.destroy()
|
|
|
|
site.addWebUser('Chantereau')
|
|
site.addWebUser('Clapies')
|
|
site.addWebUser('Febvre')
|
|
site.addWebUser('Nowicki')
|
|
return site
|
|
|
|
def generateSpSite(self, internet):
|
|
site = SpSite(self, internet, "https://service-provider/")
|
|
site.providerId = "https://service-provider/metadata"
|
|
|
|
server = lasso.Server.new(
|
|
"../../examples/data/sp-metadata.xml",
|
|
"../../examples/data/sp-public-key.pem",
|
|
"../../examples/data/sp-private-key.pem",
|
|
"../../examples/data/sp-crt.pem",
|
|
lasso.signatureMethodRsaSha1)
|
|
server.add_provider(
|
|
"../../examples/data/idp-metadata.xml",
|
|
"../../examples/data/idp-public-key.pem",
|
|
"../../examples/data/ca-crt.pem")
|
|
site.serverDump = server.dump()
|
|
self.failUnless(site.serverDump)
|
|
server.destroy()
|
|
|
|
site.addWebUser('Nicolas')
|
|
site.addWebUser('Romain')
|
|
site.addWebUser('Valery')
|
|
return site
|
|
|
|
def setUp(self):
|
|
pass
|
|
|
|
def tearDown(self):
|
|
pass
|
|
|
|
|
|
class LoginTestCase(TestCase):
|
|
def test01_generateServers(self):
|
|
"""Service provider initiated login using HTTP redirect"""
|
|
|
|
internet = Internet()
|
|
idpSite = self.generateIdpSite(internet)
|
|
spSite = self.generateSpSite(internet)
|
|
spSite.idpSite = idpSite
|
|
principal = Principal(internet, "Romain Chantereau")
|
|
principal.keyring[idpSite.url] = "Chantereau"
|
|
principal.keyring[spSite.url] = "Romain"
|
|
httpResponse = spSite.doHttpRequest(HttpRequest(principal, "GET", "/loginUsingRedirect"))
|
|
self.failUnlessEqual(httpResponse.statusCode, 200)
|
|
httpResponse = spSite.doHttpRequest(HttpRequest(principal, "GET", "/logoutUsingSoap"))
|
|
self.failUnlessEqual(httpResponse.statusCode, 200)
|
|
|
|
## def test02_spLogin(self):
|
|
## """Service provider initiated login using HTTP redirect"""
|
|
|
|
## spLogin = self.spLoginForRedirect()
|
|
## # A real service provider would issue a HTTPS redirect to spLogin.msg_url.
|
|
|
|
## # Identity provider single sign-on, for a user having no federation.
|
|
## authnRequestQuery = spLogin.msg_url.split("?", 1)[1]
|
|
## idpLogin = self.idpSingleSignOnForRedirect(authnRequestQuery, None, None)
|
|
## self.failUnless(idpLogin.must_authenticate())
|
|
## idpLoginDump = idpLogin.dump()
|
|
## # A real identity provider using a HTML form to ask user's login & password would store
|
|
## # idpLoginDump in a session variable and display the HTML login form.
|
|
|
|
## userAuthenticated = True
|
|
## authenticationMethod = lasso.samlAuthenticationMethodPassword
|
|
## idpServer = self.generateIdpServer()
|
|
## idpLogin = lasso.Login.new_from_dump(idpServer, idpLoginDump)
|
|
## #FIXME: set user and session from dump, because the logindump doesn't contain them.
|
|
## self.failUnlessEqual(idpLogin.protocolProfile, lasso.loginProtocolProfileBrwsArt)
|
|
## idpLogin = self.idpSingleSignOn_part2ForArtifactRedirect(
|
|
## idpLogin, userAuthenticated, authenticationMethod)
|
|
## # The user had no Liberty federation before, so identity must be dirty.
|
|
## self.failUnless(idpLogin.is_identity_dirty())
|
|
## idpIdentityDump = idpLogin.get_identity().dump()
|
|
## idpSessionDump = idpLogin.get_session().dump()
|
|
## nameIdentifier = idpLogin.nameIdentifier
|
|
## artifact = idpLogin.assertionArtifact
|
|
## soapResponseMsg = idpLogin.response_dump
|
|
## # A real identity provider would store idpIdentityDump in user record and store
|
|
## # idpSessionDump in session variables or user record.
|
|
## # It would then index its user record and its session using nameIdentifier.
|
|
## # It would also store soapResponseMsg and index it using artifact.
|
|
## # It would optionally create a web session (using cookie, ...).
|
|
## # And finally, it would issue a HTTPS redirect to idpLogin.msg_url.
|
|
|
|
## # Service provider assertion consumer.
|
|
## responseQuery = idpLogin.msg_url.split("?", 1)[1]
|
|
## spLogin = self.spAssertionConsumerForRedirect(responseQuery)
|
|
## # A real service provider would issue a SOAP HTTPS request containing spLogin.msg_body to
|
|
## # spLogin.msg_url.
|
|
|
|
## # Identity provider SOAP endpoint.
|
|
## idpLogin = self.idpSoapEndpointForLogin(spLogin.msg_body)
|
|
## # A real identity provider would retrieve soapResponseMsg using spLogin.assertionArtifact
|
|
## # and return it as SOAP response.
|
|
## self.failUnlessEqual(idpLogin.assertionArtifact, artifact)
|
|
|
|
## # Service provider assertion consumer (part 2: process SOAP response).
|
|
## spLogin = self.spAssertionConsumer_part2(spLogin, soapResponseMsg)
|
|
## # A real service provider would search for a user record and a session indexed by
|
|
## # spLogin.nameIdentifier.
|
|
## # In this case, we assume that the user has no Liberty federation yet => no identity dump
|
|
## # and no session dump.
|
|
## self.failUnlessEqual(spLogin.nameIdentifier, nameIdentifier)
|
|
## spLogin = self.spAssertionConsumer_part3(spLogin, None, None)
|
|
## self.failUnless(spLogin.is_identity_dirty())
|
|
## spIdentityDump = spLogin.get_identity().dump()
|
|
## spSession = spLogin.get_session()
|
|
## spSessionDump = spSession.dump()
|
|
## authenticationMethod = spSession.get_authentication_method()
|
|
## self.failUnlessEqual(authenticationMethod, lasso.samlAuthenticationMethodPassword)
|
|
## # A real service provider would store spIdentityDump in user record and spSessionDump
|
|
## # in session variables or user record.
|
|
## # It would then index its user record and its session using nameIdentifier.
|
|
## # It would create a web session (using cookie, ...).
|
|
## # And finally, it would display a page saying that Liberty authentication has succeeded.
|
|
|
|
## # Service provider logout using SOAP.
|
|
## spLogout = self.spLogoutForSoap(spIdentityDump, spSessionDump)
|
|
## # A real service provider would issue a SOAP HTTPS request containing spLogout.msg_body to
|
|
## # spLogout.msg_url.
|
|
|
|
## # Identity provider SOAP endpoint.
|
|
## idpLogout = self.idpSoapEndpointForLogout(spLogout.msg_body)
|
|
## self.failUnlessEqual(idpLogout.nameIdentifier, nameIdentifier)
|
|
## # A real identity provider would retrieve the user record and the session indexed by
|
|
## # idpLogout.nameIdentifier.
|
|
|
|
## idpLogout = self.idpSoapEndpointForLogout_part2(idpLogout, idpIdentityDump, idpSessionDump)
|
|
## # A real identity provider would store idpIdentityDump in user record and store or delete
|
|
## # idpSessionDump in session variables or user record.
|
|
## # It would then remove the nameIdentifier index to the user record and the session.
|
|
## # And finally, it would return idpLogout.msg_body as SOAP response.
|
|
|
|
## # Service provider logout (part 2: process SOAP response).
|
|
## spLogout = self.spLogoutForSoap_part2(spLogout, idpLogout.msg_body)
|
|
## self.failIf(spLogout.is_identity_dirty())
|
|
## spIdentityDump = spLogout.get_identity().dump()
|
|
## spSession = spLogout.get_session()
|
|
## # In this case, spSession should be None, but Lasso doesn't implement it yet.
|
|
## # self.failIf(spSession)
|
|
## #
|
|
## # A real service provider would store spIdentityDump in user record and store or delete
|
|
## # spSessionDump in session variables or user record.
|
|
## # It would then remove the idpLogout.nameIdentifier index to the user record and the
|
|
## # session.
|
|
## # And finally, it would display a page saying that Liberty logout has succeeded.
|
|
|
|
## def test03(self):
|
|
## """Identity provider single sign-on when identity and session already exist."""
|
|
## idpServer = self.generateIdpServer()
|
|
## idpLogin = lasso.Login.new(idpServer)
|
|
## idpIdentityDump = """\
|
|
## <LassoIdentity><LassoFederations><LassoFederation RemoteProviderID="https://service-provider:2003/liberty-alliance/metadata"><LassoLocalNameIdentifier><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">NjMxMEMzRTlEMDA4NTNEMEZGNDI1MEM0QzY4NUNBNzY=</saml:NameIdentifier></LassoLocalNameIdentifier></LassoFederation></LassoFederations></LassoIdentity>
|
|
## """.strip()
|
|
## idpLogin.set_identity_from_dump(idpIdentityDump)
|
|
## idpSessionDump = """
|
|
## <LassoSession><LassoAssertions><LassoAssertion RemoteProviderID="https://service-provider:2003/liberty-alliance/metadata"><lib:Assertion xmlns:lib="urn:liberty:iff:2003-08" AssertionID="Q0QxQzNFRTVGRTZEM0M0RjY2MTZDNTEwOUY4MDQzRTI=" MajorVersion="1" MinorVersion="2" IssueInstance="2004-08-02T18:51:43Z" Issuer="https://identity-provider:1998/liberty-alliance/metadata" InResponseTo="OEQ0OEUzODhGRTdGMEVFMzQ5Q0Q0QzYzQjk4MjUwNjQ="><lib:AuthenticationStatement xmlns:lib="urn:liberty:iff:2003-08" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2004-08-02T18:51:43Z" ReauthenticateOnOrAfter="FIXME: reauthenticateOnOrAfter"><lib:Subject xmlns:lib="urn:liberty:iff:2003-08"><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">NjMxMEMzRTlEMDA4NTNEMEZGNDI1MEM0QzY4NUNBNzY=</saml:NameIdentifier><lib:IDPProvidedNameIdentifier xmlns:lib="urn:liberty:iff:2003-08" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">NjMxMEMzRTlEMDA4NTNEMEZGNDI1MEM0QzY4NUNBNzY=</lib:IDPProvidedNameIdentifier><saml:SubjectConfirmation xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:SubjectConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:SubjectConfirmationMethod></saml:SubjectConfirmation></lib:Subject></lib:AuthenticationStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
## <SignedInfo>
|
|
## <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
## <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
## <Reference>
|
|
## <Transforms>
|
|
## <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
## </Transforms>
|
|
## <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
## <DigestValue>ZRe7eb5JuhgL6W/Le1oMezbEHnA=</DigestValue>
|
|
## </Reference>
|
|
## </SignedInfo>
|
|
## <SignatureValue>CYOtlOvHtpkQsLA87GrtHs1WuoPVXHiPkVsmce2X1+PUslYpKLKp3cuNTVo1Z7+k
|
|
## Iku+DThYC9EvR7gprVQW2Y3CpCPanWs2A6j21SrlfqGFffpUtOFuiv3L1rfGKjPJ
|
|
## eMWehfc/SEi3+/JT22RejeYrSA61YLwsfItB7Ie4L0TRuZuxxu++CsidIEu2iv7l
|
|
## fI79SMn5hF7j/oFU9IODFhCArNLgBiOxA9rnRNvXwRFFmRN3qvdEuXuAZBthRhoa
|
|
## BRcL2T7tLxIVV+8y1fUjkliV1QgvOeus9g1bib1FLHdzHZ6KNGLPkZiXuM7ZPT1B
|
|
## G8WStJalTeH81AE7Ol4pcg==</SignatureValue>
|
|
## <KeyInfo>
|
|
## <X509Data>
|
|
## <X509Certificate>MIIDKTCCAhECAQEwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCSVQxDzANBgNV
|
|
## BAcTBlBvbXBlaTEQMA4GA1UEChMHVmVzdXZpbzEpMCcGA1UEAxMgVmVzdXZpbyBM
|
|
## aWJlcnR5IEFsbGlhbmNlIFJvb3QgQ0EwHhcNMDQwNDIwMTQwMzQ1WhcNMDUwNDIw
|
|
## MTQwMzQ1WjBaMQswCQYDVQQGEwJJVDEPMA0GA1UEBxMGUG9tcGVpMR4wHAYDVQQK
|
|
## ExVJZGVudGl0eSBQcm92aWRlciBJbmMxGjAYBgNVBAMTEWlkZW50aXR5LXByb3Zp
|
|
## ZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SGH3FPnhpQ8rCED
|
|
## RmC+NEkJQ6ZrG1jRL1kNx3wNu1xRZgFPiEDFnu9p/muVQkRAzK4txgC5i0ymwgRZ
|
|
## uan2yFrdq7Kpc9r0cM1S/q63aQeOMXQszz6G0NIY9DOzdrdlTc2uToBpIPA4a/Tf
|
|
## NWpMFZ7zGB9ThJ4+S5MAIA6y3SRWYHOqdlwjo/R0P4C3y8wIClgI0ZTdS6/Rkr59
|
|
## XC4WRocMzGCSsk+1F1tAZoR77ummLcY4nFkbtawyeRXEUpSpDaxgVEEmvH+/Kqx5
|
|
## NhVzeCZkm8szOzMea+QT4Uh3F7GVwY/7+JV23eCGyr2n3EhXgCqw0nnGSGR7vrNl
|
|
## Ue1oswIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQAFyYC/V49X7ZNLpYI8jx1TE9X3
|
|
## J4c47cCLaxslrhi0/X6nCOEcBckXtbL+ZhIiHfI6PWizHMjTCEkJOYMVOsXyWN73
|
|
## XdzfIZVrThQRsYvQZqUH8cZZH3fFg/RyEM3fzlFDsuIxfg7+NIDNmSFbt/YdFL0T
|
|
## 3sB7jYSkKr4buX9ZewdOfRxwN4MZIE32SoBo+UOgNrMM2hcQTStBK09vzJiWQE/4
|
|
## aWbZJT9jtBPGWTsMS8g1x9WAmJHV2BpUiSfY39895a5T7kbbqZ3rp7DM9dgLjdXC
|
|
## jFL7NhzvY02aBTLhm22YOLYnlycKm64NGne+siooDCi5tel2/vcx+e+btX9x</X509Certificate>
|
|
## </X509Data>
|
|
## </KeyInfo>
|
|
## </Signature></lib:Assertion></LassoAssertion></LassoAssertions></LassoSession>
|
|
## """.strip()
|
|
## # " <-- Trick for Emacs Python mode.
|
|
## idpLogin.set_session_from_dump(idpSessionDump)
|
|
## authnRequestQuery = """NameIDPolicy=federated&IsPassive=false&ProviderID=https%3A%2F%2Fservice-provider%3A2003%2Fliberty-alliance%2Fmetadata&consent=urn%3Aliberty%3Aconsent%3Aobtained&IssueInstance=2004-08-02T20%3A33%3A58Z&MinorVersion=2&MajorVersion=1&RequestID=ODVGNkUyMzY5N0MzOTY4QzZGOUYyNzEwRTJGMUNCQTI%3D&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=fnSL5Mgp%2BV%2FtdUuYQJmFKvFY8eEco6sypmejvP4sD0v5ApywV94mUo6BxE29o1KW%0AGFXiMG7puhTwRSlKDo1vlh5iHNqVfjKcbx2XhfoDfplqLir102dyHxB5GedEQvqw%0AbTFtFrB6SnHi5facrYHCn7b58CxAWv9XW4DIfcVCOSma2OOBCm%2FzzCSiZpOtbRk9%0AveQzace41tDW0XLlbRdWpvwsma0yaYSkqYvTV3hmvgkWS5x9lzcm97oME4ywzwbU%0AJAyG8BkqMFoG7FPjwzR8qh7%2FWi%2BCzxxqfczxSGkUZUmsQdxyxazjhDpt1X8i5fan%0AnaF1vWF3GmS6G4t7mrkItA%3D%3D"""
|
|
## method = lasso.httpMethodRedirect
|
|
## idpLogin.init_from_authn_request_msg(authnRequestQuery, method)
|
|
## self.failIf(idpLogin.must_authenticate())
|
|
## userAuthenticated = True
|
|
## authenticationMethod = lasso.samlAuthenticationMethodPassword
|
|
## self.failUnlessEqual(idpLogin.protocolProfile, lasso.loginProtocolProfileBrwsArt)
|
|
## idpLogin.build_artifact_msg(
|
|
## userAuthenticated, authenticationMethod, "FIXME: reauthenticateOnOrAfter",
|
|
## lasso.httpMethodRedirect)
|
|
## self.failUnless(idpLogin.msg_url)
|
|
## self.failUnless(idpLogin.assertionArtifact)
|
|
## self.failUnless(idpLogin.response_dump)
|
|
## self.failUnless(idpLogin.nameIdentifier)
|
|
|
|
## def test04(self):
|
|
## """Identity provider logout."""
|
|
## idpServer = self.generateIdpServer()
|
|
## soapRequestMessage = """\
|
|
## <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><lib:LogoutRequest xmlns:lib="urn:liberty:iff:2003-08" RequestID="RDIwMUYzM0Q1MzdFMjMzQzk0NTM4QUNEQUQ0MURBMEE=" MajorVersion="1" MinorVersion="2" IssueInstance="2004-08-03T11:56:15Z"><lib:ProviderID>https://service-provider:2003/liberty-alliance/metadata</lib:ProviderID><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">QkM3M0M4MTYxREQzNEYwNEI4M0I4MUVERDUyQUUyMjA=</saml:NameIdentifier><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
## <SignedInfo>
|
|
## <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
## <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
## <Reference>
|
|
## <Transforms>
|
|
## <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
## </Transforms>
|
|
## <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
## <DigestValue>NlVszQnxIyPU7zbJYadQmTnFAsI=</DigestValue>
|
|
## </Reference>
|
|
## </SignedInfo>
|
|
## <SignatureValue>h0lB2hBstgxlNYnVQ4xzmXIi2APqNxKEEfUqYm3NeGmddbazg0/Y/SdcqLlto9fy
|
|
## ML34w/TJG7DnCdeUQVxdxhzmJlv3X2U5qDAYh6gX4g36wJCntderC5LtNkZhhTWt
|
|
## m9NWGszFhCm9nSaGATdj4JGqJNc+LUIt3EvXHDIqQ/LU2g3hxZQ4Hs5Fg9yqRS98
|
|
## 5CWPtckYcGPcG8kFuTKNos2F4KQPyXJRX0KF+9FbkBX0RsblstzL0CiFUlor4m+R
|
|
## ejvMcEt/nGCGj7F5mRPYcW3ZxTw4J2wAqS52Tu41fyeKw5SHIJQNmwV25P/hINim
|
|
## hd2ybn/G3vK2If0+rUjA8Q==</SignatureValue>
|
|
## <KeyInfo>
|
|
## <X509Data>
|
|
## <X509Certificate>MIIDJzCCAg8CAQIwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCSVQxDzANBgNV
|
|
## BAcTBlBvbXBlaTEQMA4GA1UEChMHVmVzdXZpbzEpMCcGA1UEAxMgVmVzdXZpbyBM
|
|
## aWJlcnR5IEFsbGlhbmNlIFJvb3QgQ0EwHhcNMDQwNDIwMTQyMDMxWhcNMDUwNDIw
|
|
## MTQyMDMxWjBYMQswCQYDVQQGEwJJVDEPMA0GA1UEBxMGUG9tcGVpMR0wGwYDVQQK
|
|
## ExRTZXJ2aWNlIFByb3ZpZGVyIEluYzEZMBcGA1UEAxMQc2VydmljZS1wcm92aWRl
|
|
## cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALIjOIroSVwUaMOyFlGL
|
|
## p6oCDkI14ssZRec/l2Z+p89kwVF+vkyhE7LHkaIgE1RnmPhcudzMCNFc6okpHdtV
|
|
## yU+GTSXhRN7/BGYBoDpfNpTMP0aUpw/BQOhL+zeb0nSsSf7ejNeKyvR+q5ia+3N4
|
|
## dm9vgUPWZk0iN0URMSRxzIA3nEsR+B9JV7BFFyfbBxwLR4Aht667cuSeFnAUnynp
|
|
## JiHiKF/r5yXk+EKK++8NpjflpJnFVT1mSfj+6iYutiOrgUKgCANsaXr0WomR4oKg
|
|
## kqzP2DLDwnwi73vUAW4y9CBNk7nDtZJFhUxKa63i1HgHCKNvHfVjvKPz844PnLw/
|
|
## CWMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAOfAVexQY2ImgBWjcAkGAYfLwMZ2k
|
|
## 8jtQGRgbPuD1DBQ+oZm+Ykuw30orVAo8/S5PcSNdRawOVoTY60oRupGBctoqSzmp
|
|
## SiBkWOwb4wBZOHfSNRFDS83N0ewHk4FFY6t5NPlhUORC07xl4GaVUb5LjyDKMh2j
|
|
## RtLaR85lCV8xVvM+jdBzBM2FxOQ0WdhphMjO4gj5ene791iT4PpA69o7wuZ9g728
|
|
## CGb/HRUx5EPgbIy52G224ITlQWadD1Z6y4PFTowDjkaRVerjUVRJZ/a5QVNsI4Du
|
|
## /z71zAbdg4NfTfXjAXHRhEGappHVBROAQFchQ0oKhCTkICN4TUSuodgy/A==</X509Certificate>
|
|
## </X509Data>
|
|
## </KeyInfo>
|
|
## </Signature></lib:LogoutRequest></soap-env:Body></soap-env:Envelope>
|
|
## """.strip()
|
|
## # " <-- Trick for Emacs Python mode.
|
|
## requestType = lasso.get_request_type_from_soap_msg(soapRequestMessage)
|
|
## self.failUnlessEqual(requestType, lasso.requestTypeLogout)
|
|
## idpLogout = lasso.Logout.new(idpServer, lasso.providerTypeIdp)
|
|
## idpLogout.process_request_msg(soapRequestMessage, lasso.httpMethodSoap)
|
|
## self.failUnless(idpLogout.nameIdentifier)
|
|
## idpIdentityDump = """\
|
|
## <LassoIdentity><LassoFederations><LassoFederation RemoteProviderID="https://service-provider:2003/liberty-alliance/metadata"><LassoLocalNameIdentifier><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">QkM3M0M4MTYxREQzNEYwNEI4M0I4MUVERDUyQUUyMjA=</saml:NameIdentifier></LassoLocalNameIdentifier></LassoFederation></LassoFederations></LassoIdentity>
|
|
## """.strip()
|
|
## idpLogout.set_identity_from_dump(idpIdentityDump)
|
|
## self.failUnlessEqual(idpLogout.get_identity().dump(), idpIdentityDump)
|
|
## idpSessionDump = """
|
|
## <LassoSession><LassoAssertions><LassoAssertion RemoteProviderID="https://service-provider:2003/liberty-alliance/metadata"><lib:Assertion xmlns:lib="urn:liberty:iff:2003-08" AssertionID="QUVENUJCNzRFOUQ3MEZFNEYzNUUwQTA5OTRGMEYzMDg=" MajorVersion="1" MinorVersion="2" IssueInstance="2004-08-03T11:55:55Z" Issuer="https://identity-provider:1998/liberty-alliance/metadata" InResponseTo="N0VEQzE0QUE1NTYwQTAzRjk4Njk3Q0JCRUU0RUZCQkY="><lib:AuthenticationStatement xmlns:lib="urn:liberty:iff:2003-08" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2004-08-03T11:55:55Z" ReauthenticateOnOrAfter="FIXME: reauthenticateOnOrAfter"><lib:Subject xmlns:lib="urn:liberty:iff:2003-08"><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">QkM3M0M4MTYxREQzNEYwNEI4M0I4MUVERDUyQUUyMjA=</saml:NameIdentifier><lib:IDPProvidedNameIdentifier xmlns:lib="urn:liberty:iff:2003-08" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">QkM3M0M4MTYxREQzNEYwNEI4M0I4MUVERDUyQUUyMjA=</lib:IDPProvidedNameIdentifier><saml:SubjectConfirmation xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:SubjectConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:SubjectConfirmationMethod></saml:SubjectConfirmation></lib:Subject></lib:AuthenticationStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
## <SignedInfo>
|
|
## <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
## <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
## <Reference>
|
|
## <Transforms>
|
|
## <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
## </Transforms>
|
|
## <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
## <DigestValue>TqCKQTLsexix/tIqEabjBPcYby8=</DigestValue>
|
|
## </Reference>
|
|
## </SignedInfo>
|
|
## <SignatureValue>l96xDhc0/nevhvx79eyYvGknXDJMcykiomKOLMiL0FcxOglaKi/aNOGNA5VdT0mh
|
|
## EdlAynOOVy9xXphy9kLyXXSMcYV5UMeqCIi0ro5cvMP1xBfEqBHAHaYQR+TXbGdn
|
|
## bPCkIvGwzLDVr8bvwWnPjHqaXffswlfzjrDYq726Sx37s3UBgcViEVG0HTGe2X+f
|
|
## Kx2iahOjVLvR9bBWOdsiKNisK3GtZPGFmxIXALg8oZnwJA4JKodzh+o1synKoLn3
|
|
## 2WigVh7r43LISSkCHx1C7qIK2zFz8YtPtaHa4xfMWT6QwZRngsXRcUcUibWZyoYt
|
|
## 950ly3lp1XkexL0uRXPvKw==</SignatureValue>
|
|
## <KeyInfo>
|
|
## <X509Data>
|
|
## <X509Certificate>MIIDKTCCAhECAQEwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCSVQxDzANBgNV
|
|
## BAcTBlBvbXBlaTEQMA4GA1UEChMHVmVzdXZpbzEpMCcGA1UEAxMgVmVzdXZpbyBM
|
|
## aWJlcnR5IEFsbGlhbmNlIFJvb3QgQ0EwHhcNMDQwNDIwMTQwMzQ1WhcNMDUwNDIw
|
|
## MTQwMzQ1WjBaMQswCQYDVQQGEwJJVDEPMA0GA1UEBxMGUG9tcGVpMR4wHAYDVQQK
|
|
## ExVJZGVudGl0eSBQcm92aWRlciBJbmMxGjAYBgNVBAMTEWlkZW50aXR5LXByb3Zp
|
|
## ZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SGH3FPnhpQ8rCED
|
|
## RmC+NEkJQ6ZrG1jRL1kNx3wNu1xRZgFPiEDFnu9p/muVQkRAzK4txgC5i0ymwgRZ
|
|
## uan2yFrdq7Kpc9r0cM1S/q63aQeOMXQszz6G0NIY9DOzdrdlTc2uToBpIPA4a/Tf
|
|
## NWpMFZ7zGB9ThJ4+S5MAIA6y3SRWYHOqdlwjo/R0P4C3y8wIClgI0ZTdS6/Rkr59
|
|
## XC4WRocMzGCSsk+1F1tAZoR77ummLcY4nFkbtawyeRXEUpSpDaxgVEEmvH+/Kqx5
|
|
## NhVzeCZkm8szOzMea+QT4Uh3F7GVwY/7+JV23eCGyr2n3EhXgCqw0nnGSGR7vrNl
|
|
## Ue1oswIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQAFyYC/V49X7ZNLpYI8jx1TE9X3
|
|
## J4c47cCLaxslrhi0/X6nCOEcBckXtbL+ZhIiHfI6PWizHMjTCEkJOYMVOsXyWN73
|
|
## XdzfIZVrThQRsYvQZqUH8cZZH3fFg/RyEM3fzlFDsuIxfg7+NIDNmSFbt/YdFL0T
|
|
## 3sB7jYSkKr4buX9ZewdOfRxwN4MZIE32SoBo+UOgNrMM2hcQTStBK09vzJiWQE/4
|
|
## aWbZJT9jtBPGWTsMS8g1x9WAmJHV2BpUiSfY39895a5T7kbbqZ3rp7DM9dgLjdXC
|
|
## jFL7NhzvY02aBTLhm22YOLYnlycKm64NGne+siooDCi5tel2/vcx+e+btX9x</X509Certificate>
|
|
## </X509Data>
|
|
## </KeyInfo>
|
|
## </Signature></lib:Assertion></LassoAssertion></LassoAssertions></LassoSession>
|
|
## """.strip()
|
|
## # " <-- Trick for Emacs Python mode.
|
|
## idpLogout.set_session_from_dump(idpSessionDump)
|
|
## self.failUnlessEqual(idpLogout.get_session().dump(), idpSessionDump)
|
|
## idpLogout.validate_request()
|
|
## self.failIf(idpLogout.is_identity_dirty())
|
|
## self.failUnless(idpLogout.is_session_dirty())
|
|
## idpSessionDump = idpLogout.get_session().dump()
|
|
## self.failUnless(idpSessionDump)
|
|
## self.failIf(idpLogout.get_next_providerID())
|
|
## idpLogout.build_response_msg()
|
|
## soapResponseMsg = idpLogout.msg_body
|
|
## self.failUnless(soapResponseMsg)
|
|
|
|
## def test05(self):
|
|
## """Service provider logout."""
|
|
## spServer = self.getServer()
|
|
## spLogout = lasso.Logout.new(spServer, lasso.providerTypeSp)
|
|
|
|
## spIdentityDump = """\
|
|
## <LassoIdentity><LassoFederations><LassoFederation RemoteProviderID="https://identity-provider:1998/liberty-alliance/metadata"><LassoRemoteNameIdentifier><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">RTE5REZDN0UyMEJEQzA0MDQxRjM3NThCQkFCNERCODQ=</saml:NameIdentifier></LassoRemoteNameIdentifier><LassoLocalNameIdentifier><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">RTE5REZDN0UyMEJEQzA0MDQxRjM3NThCQkFCNERCODQ=</saml:NameIdentifier></LassoLocalNameIdentifier></LassoFederation></LassoFederations></LassoIdentity>
|
|
## """.strip()
|
|
## spLogout.set_identity_from_dump(spIdentityDump)
|
|
|
|
## spSessionDump = """\
|
|
## <LassoSession><LassoAssertions><LassoAssertion RemoteProviderID="https://identity-provider:1998/liberty-alliance/metadata"><lib:Assertion xmlns:lib="urn:liberty:iff:2003-08" AssertionID="QzQ3NkVCMEIzNTY0RDNBOUVEQkNDN0RCQjA1MjlFRTA=" MajorVersion="1" MinorVersion="2" IssueInstance="2004-08-04T00:03:08Z" Issuer="https://identity-provider:1998/liberty-alliance/metadata" InResponseTo="M0M3Q0RBREE4QjQ1OTAwOTk2QTlFN0RFRUU0NTNGNUM="><lib:AuthenticationStatement xmlns:lib="urn:liberty:iff:2003-08" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2004-08-04T00:03:08Z" ReauthenticateOnOrAfter="FIXME: reauthenticateOnOrAfter"><lib:Subject xmlns:lib="urn:liberty:iff:2003-08"><saml:NameIdentifier xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">RTE5REZDN0UyMEJEQzA0MDQxRjM3NThCQkFCNERCODQ=</saml:NameIdentifier><lib:IDPProvidedNameIdentifier xmlns:lib="urn:liberty:iff:2003-08" NameQualifier="https://identity-provider:1998/liberty-alliance/metadata" Format="urn:liberty:iff:nameid:federated">RTE5REZDN0UyMEJEQzA0MDQxRjM3NThCQkFCNERCODQ=</lib:IDPProvidedNameIdentifier><saml:SubjectConfirmation xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"><saml:SubjectConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:SubjectConfirmationMethod></saml:SubjectConfirmation></lib:Subject></lib:AuthenticationStatement><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
## <SignedInfo>
|
|
## <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
## <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
## <Reference>
|
|
## <Transforms>
|
|
## <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
## </Transforms>
|
|
## <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
## <DigestValue>8BSywvR2YB/euz8CCEhElQRSiZA=</DigestValue>
|
|
## </Reference>
|
|
## </SignedInfo>
|
|
## <SignatureValue>Vg0BM0Z15mFsRxEOhy9oCfXuK/NgQPrgJc2Kf3tE9g/uTnNFGq0YNB5KSlonJLUr
|
|
## 0cZ8D18XlTJrZp22vPCUO44hvL5DDWGTctqJbl+TV3D8qzFlfe8XOPBy3cUSXcYo
|
|
## E4qR44SnA9iZeRH0t4c3+8lY+BeXoqcglBrpE86B5Ftfb7wvLY0m8fdzPSJneSqq
|
|
## Z41uh4Wtegq4bqIkUev0nrY1wKHJjkfpKNmcirGTNm0gm8c/Ki9UCgI9g4cknj+F
|
|
## /UR8LQH/H8u2YSp3w5wiWfcmEfjfoVqa8YoiwWAoRgkKRVwER6iXYdqJ9vF0GFN/
|
|
## Bm7OmEnDwF3bc/fruca4Pg==</SignatureValue>
|
|
## <KeyInfo>
|
|
## <X509Data>
|
|
## <X509Certificate>MIIDKTCCAhECAQEwDQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCSVQxDzANBgNV
|
|
## BAcTBlBvbXBlaTEQMA4GA1UEChMHVmVzdXZpbzEpMCcGA1UEAxMgVmVzdXZpbyBM
|
|
## aWJlcnR5IEFsbGlhbmNlIFJvb3QgQ0EwHhcNMDQwNDIwMTQwMzQ1WhcNMDUwNDIw
|
|
## MTQwMzQ1WjBaMQswCQYDVQQGEwJJVDEPMA0GA1UEBxMGUG9tcGVpMR4wHAYDVQQK
|
|
## ExVJZGVudGl0eSBQcm92aWRlciBJbmMxGjAYBgNVBAMTEWlkZW50aXR5LXByb3Zp
|
|
## ZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SGH3FPnhpQ8rCED
|
|
## RmC+NEkJQ6ZrG1jRL1kNx3wNu1xRZgFPiEDFnu9p/muVQkRAzK4txgC5i0ymwgRZ
|
|
## uan2yFrdq7Kpc9r0cM1S/q63aQeOMXQszz6G0NIY9DOzdrdlTc2uToBpIPA4a/Tf
|
|
## NWpMFZ7zGB9ThJ4+S5MAIA6y3SRWYHOqdlwjo/R0P4C3y8wIClgI0ZTdS6/Rkr59
|
|
## XC4WRocMzGCSsk+1F1tAZoR77ummLcY4nFkbtawyeRXEUpSpDaxgVEEmvH+/Kqx5
|
|
## NhVzeCZkm8szOzMea+QT4Uh3F7GVwY/7+JV23eCGyr2n3EhXgCqw0nnGSGR7vrNl
|
|
## Ue1oswIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQAFyYC/V49X7ZNLpYI8jx1TE9X3
|
|
## J4c47cCLaxslrhi0/X6nCOEcBckXtbL+ZhIiHfI6PWizHMjTCEkJOYMVOsXyWN73
|
|
## XdzfIZVrThQRsYvQZqUH8cZZH3fFg/RyEM3fzlFDsuIxfg7+NIDNmSFbt/YdFL0T
|
|
## 3sB7jYSkKr4buX9ZewdOfRxwN4MZIE32SoBo+UOgNrMM2hcQTStBK09vzJiWQE/4
|
|
## aWbZJT9jtBPGWTsMS8g1x9WAmJHV2BpUiSfY39895a5T7kbbqZ3rp7DM9dgLjdXC
|
|
## jFL7NhzvY02aBTLhm22YOLYnlycKm64NGne+siooDCi5tel2/vcx+e+btX9x</X509Certificate>
|
|
## </X509Data>
|
|
## </KeyInfo>
|
|
## </Signature></lib:Assertion></LassoAssertion></LassoAssertions></LassoSession>
|
|
## """.strip()
|
|
## # " <-- Trick for Emacs Python mode.
|
|
## spLogout.set_session_from_dump(spSessionDump)
|
|
|
|
## spLogout.init_request()
|
|
## spLogout.build_request_msg()
|
|
## self.failUnless(spLogout.msg_url)
|
|
## self.failUnless(spLogout.msg_body)
|
|
## self.failUnless(spLogout.nameIdentifier)
|
|
|
|
## soapResponseMessage = """\
|
|
## <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><lib:LogoutResponse xmlns:lib="urn:liberty:iff:2003-08" ResponseID="NjcyNDYxQ0FCRTQwMUE0NjE4MzlFQjFDOTI2MTc3NjE=" MajorVersion="1" MinorVersion="2" IssueInstance="2004-08-04T00:03:20Z" InResponseTo="MzNCOTRBMjRCMDExN0MxODc1MUI5NjMwQjlCMTg1NzM=" Recipient="https://service-provider:2003/liberty-alliance/metadata"><lib:ProviderID>https://identity-provider:1998/liberty-alliance/metadata</lib:ProviderID><samlp:Status xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"><samlp:StatusCode xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" Value="Samlp:Success"/></samlp:Status></lib:LogoutResponse></soap-env:Body></soap-env:Envelope>
|
|
## """.strip()
|
|
## spLogout.process_response_msg(soapResponseMessage, lasso.httpMethodSoap)
|
|
## self.failIf(spLogout.is_identity_dirty())
|
|
## self.failUnless(spLogout.is_session_dirty())
|
|
## spSessionDump = spLogout.get_session().dump()
|
|
## # self.failIf(spSessionDump)
|
|
|
|
## def test06(self):
|
|
## """Service provider LECP login."""
|
|
|
|
## # LECP has asked service provider for login.
|
|
## spServer = self.getServer()
|
|
|
|
## # FIXME: Why doesn't lasso.Lecp.new have spServer as argument?
|
|
## # spLecp = lasso.Lecp.new(spServer)
|
|
## spLecp = lasso.Lecp.new()
|
|
## spLecp.init_authn_request_envelope(sp, )
|
|
## lasso_lecp_init_authn_request_envelope(sp_lecp, spserver, authnRequest);
|
|
## lasso_lecp_build_authn_request_envelope_msg(sp_lecp);
|
|
## msg = g_strdup(sp_lecp->msg_body);
|
|
## lasso_lecp_destroy(sp_lecp);
|
|
|
|
|
|
suite1 = unittest.makeSuite(LoginTestCase, 'test')
|
|
|
|
allTests = unittest.TestSuite((suite1,))
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(not unittest.TextTestRunner(verbosity=2).run(allTests).wasSuccessful())
|
|
|