Merge pull request #27 from dv10den/master

Added documentation structure
This commit is contained in:
Roland Hedberg
2014-04-05 02:37:38 +02:00
33 changed files with 679 additions and 740 deletions

BIN
doc/_static/ViewmeonGitHub.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -12,6 +12,7 @@
# serve to show the default. # serve to show the default.
import sys, os import sys, os
import alabaster
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
@@ -25,7 +26,7 @@ import sys, os
# Add any Sphinx extension module names here, as strings. They can be extensions # Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] extensions = ['alabaster', 'sphinx.ext.autodoc', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ['_templates']
@@ -91,7 +92,25 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
html_theme = 'default' html_theme_path = [alabaster.get_path()]
html_theme = 'alabaster'
html_sidebars = {
'**': [
'about.html',
'navigation.html',
'searchbox.html',
'donate.html',
]
}
html_theme_options = {
'description': '',
'github_button': False,
'github_user': 'its-dirg',
'github_repo': 'IdProxy',
'github_banner': False,
}
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the

View File

@@ -206,7 +206,7 @@ Running the script testing an IDP
Synopsis:: Synopsis::
$ idp_testdrv.py --help $ idp_testdrv.py --help
usage: idp_testdrv.py [-h] [-d] [-H] [-i] [-C CA_CERTS] [-J TT_CONFIG_FILE] [-m] [-l] usage: idp_testdrv.py [-h] [-d] [-H] [-C CA_CERTS] [-J TT_CONFIG_FILE] [-m] [-l]
[-c TD_CONFIG] [-c TD_CONFIG]
[oper] [oper]
@@ -215,15 +215,14 @@ Synopsis::
optional arguments: optional arguments:
-C CA_CERTS CA certs to use to verify HTTPS server certificates, if -C CA_CERTS CA certs to use to verify HTTPS server certificates, if
HTTPS is used and server certs are passed with -C then HTTPS is used and no server CA certs are defined then
the default cert verification will be done using keys/cacert.pem, no cert verification will be done. For a generic validation you may use the ca_bundle.crt
which is derived from Mozilla's ca_bundle.crt. file that comes with Mozilla.
-c TD_CONFIG, --config Test driver configuration module at the current directory or the path specified -c TD_CONFIG, --config Test driver configuration module at the current directory or the path specified
with the -P option. Do not use relative paths or the .py filename extension with the -P option. Do not use relative paths or the .py filename extension
-d, --debug Print debug information to stderr -d, --debug Print debug information to stderr
-H, --prettyprint Human readable status output -H, --prettyprint Human readable status output
-h, --help show this help message and exit -h, --help show this help message and exit
-i, --insecure do not check TLS certificate (overriding -C option)
-J TT_CONFIG_FILE Test target configuration in JSON format -J TT_CONFIG_FILE Test target configuration in JSON format
-L, --log Print HTTP log information # TODO: update documentation -L, --log Print HTTP log information # TODO: update documentation
-l, --list List all the test operations as a JSON object -l, --list List all the test operations as a JSON object
@@ -242,22 +241,20 @@ Running the script testing an SP
Synopsis:: Synopsis::
$ sp_testdrv.py --help $ sp_testdrv.py --help
usage: sp_testdrv.py [-h] [-d] [-C CA_CERTS] [-i] [-J TT_CONFIG_FILE] [-m] [-l] [-c TD_CONFIG] [-t TEST_PACKAGE] [oper] usage: sp_testdrv.py [-h] [-d] [-C CA_CERTS] [-J TT_CONFIG_FILE] [-m] [-l] [-c TD_CONFIG] [oper]
positional arguments: positional arguments:
oper Which test to run (mandatory except for options -h, -l and -m) oper Which test to run (mandatory except for options -h, -l and -m)
optional arguments: optional arguments:
-C CA_CERTS CA certs to use to verify HTTPS server certificates, if -C CA_CERTS CA certs to use to verify HTTPS server certificates, if
HTTPS is used and server certs are passed with -C then HTTPS is used and no server CA certs are defined then
the default cert verification will be done using keys/cacert.pem, no cert verification will be done. For a generic validation you may use the ca_bundle.crt
which is derived from Mozilla's ca_bundle.crt. file that comes with Mozilla.
-c TD_CONFIG, --config Test driver configuration module at the current directory or the path specified -c TD_CONFIG, --config Test driver configuration module at the current directory or the path specified
with the -P option. Do not use relative paths or filename extension with the -P option. Do not use relative paths or filename extension
-d, --debug Print debug information to stderr -d, --debug Print debug information to stderr
-H, --prettyprint Human readable status output
-h, --help show this help message and exit -h, --help show this help message and exit
-i, --insecure do not check TLS certificate (overriding -C option)
-J TT_CONFIG_FILE Test target configuration in JSON format -J TT_CONFIG_FILE Test target configuration in JSON format
-L, --log Print HTTP log information # TODO: update documentation -L, --log Print HTTP log information # TODO: update documentation
-l, --list List all the test flows as a JSON object -l, --list List all the test flows as a JSON object

View File

@@ -18,6 +18,7 @@ Contents:
howto howto
install install
saml2test
Indices and tables Indices and tables
================== ==================
@@ -26,3 +27,8 @@ Indices and tables
* :ref:`modindex` * :ref:`modindex`
* :ref:`search` * :ref:`search`
.. raw:: html
<a href="https://github.com/rohe/saml2test" class="github" target="_blank">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="_static/ViewmeonGitHub.png" alt="Fork me on GitHub" class="github"/>
</a>

5
doc/make.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/sh
rm -f saml2test*
sphinx-apidoc -F -o ../doc/ ../src/saml2test
make clean
make html

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
__author__ = 'rohe0002' __author__ = 'rohe0002'
from sp_test import tests
from sp_test import Client from sp_test import Client
from sp_test.check import factory from sp_test.check import factory
cli = Client(factory) cli = Client(tests, factory)
cli.run() cli.run()

View File

@@ -21,19 +21,18 @@ __author__ = 'rohe0002'
setup( setup(
name="saml2test", name="saml2test",
version="0.5.0beta", version="0.4.3",
description="SAML2 test tool", description="SAML2 test tool",
author = "Roland Hedberg", author = "Roland Hedberg",
author_email = "roland.hedberg@adm.umu.se", author_email = "roland.hedberg@adm.umu.se",
license="Apache 2.0", license="Apache 2.0",
packages=["idp_test", "idp_test/package", "saml2test", "sp_test", packages=["idp_test", "idp_test/package", "saml2test", "sp_test"],
"sp_test/test_suites"],
package_dir = {"": "src"}, package_dir = {"": "src"},
classifiers = [ classifiers = [
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",
"License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: Apache Software License",
"Topic :: Software Development :: Libraries :: Python Modules"], "Topic :: Software Development :: Libraries :: Python Modules"],
install_requires = ["pysaml2 >= 2", install_requires = ["pysaml2",
"mechanize", "mechanize",
"argparse", "argparse",
"beautifulsoup4", "beautifulsoup4",

View File

@@ -19,10 +19,9 @@ from saml2.mdstore import MetaData
from saml2test import FatalError, OperationError from saml2test import FatalError, OperationError
from saml2test import exception_trace from saml2test import exception_trace
from saml2test import ContextFilter from saml2test import ContextFilter
from saml2test import JSON_DUMPS_ARGS
from base import Conversation from idp_test.base import Conversation
from check import CheckSaml2IntMetaData from idp_test.check import CheckSaml2IntMetaData
# Schemas supported # Schemas supported
from saml2 import md from saml2 import md
@@ -40,12 +39,10 @@ SCHEMA = [dri, idpdisc, md, mdattr, mdui, saml, ui, xmldsig, xmlenc]
__author__ = 'rolandh' __author__ = 'rolandh'
#logger = logging.getLogger("") logger = logging.getLogger("")
#logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
#formatter = logging.Formatter("%(asctime)s %(name)s:%(levelname)s " #formatter = logging.Formatter("%(asctime)s %(name)s:%(levelname)s %(message)s")
#"%(message)s") formatter_2 = logging.Formatter("%(delta).6f - %(levelname)s - [%(name)s] %(message)s")
formatter_2 = logging.Formatter("%(delta).6f - %(levelname)s - [%(name)s] "
"%(message)s")
cf = ContextFilter() cf = ContextFilter()
cf.start() cf.start()
@@ -53,20 +50,12 @@ cf.start()
streamhandler = logging.StreamHandler(sys.stderr) streamhandler = logging.StreamHandler(sys.stderr)
streamhandler.setFormatter(formatter_2) streamhandler.setFormatter(formatter_2)
memoryhandler = logging.handlers.MemoryHandler(1024 * 10, logging.DEBUG) memoryhandler = logging.handlers.MemoryHandler(1024*10, logging.DEBUG)
memoryhandler.addFilter(cf) memoryhandler.addFilter(cf)
#saml2testlog = logging.getLogger("saml2test") saml2testlog = logging.getLogger("saml2test")
#saml2testlog.addHandler(memoryhandler) saml2testlog.addHandler(memoryhandler)
#saml2testlog.setLevel(logging.DEBUG) saml2testlog.setLevel(logging.DEBUG)
logger = logging.getLogger("saml2test")
logger.setLevel(logging.DEBUG)
logger.addHandler(memoryhandler)
# The streamhandler variable should be added to the logger if
# you want to see the log messages as they are printed instead
# of afterwards (mostly useful during debugging
#logger.addHandler(streamhandler)
logger.setLevel(logging.DEBUG)
def recursive_find_module(name, path=None): def recursive_find_module(name, path=None):
@@ -116,9 +105,9 @@ class SAML2client(object):
self._parser.add_argument('-L', dest='log', action='store_true', self._parser.add_argument('-L', dest='log', action='store_true',
help="Print log information") help="Print log information")
self._parser.add_argument( self._parser.add_argument(
'-C', dest="ca_certs", '-C', dest="§",
help=("CA certs to use to verify HTTPS server certificates, " help=("CA certs to use to verify HTTPS server certificates, ",
"if HTTPS is used and no server CA certs are defined then " "if HTTPS is used and no server CA certs are defined then ",
"no cert verification will be done")) "no cert verification will be done"))
self._parser.add_argument('-J', dest="json_config_file", self._parser.add_argument('-J', dest="json_config_file",
help="Script configuration") help="Script configuration")
@@ -151,7 +140,6 @@ class SAML2client(object):
self.constraints = {} self.constraints = {}
self.operations = None self.operations = None
self.args = None self.args = None
self.client = None
def json_config_file(self): def json_config_file(self):
if self.args.json_config_file == "-": if self.args.json_config_file == "-":
@@ -219,7 +207,7 @@ class SAML2client(object):
try: try:
self.entity_id = _jc["entity_id"] self.entity_id = _jc["entity_id"]
# Verify its the correct metadata # Verify its the correct metadata
assert self.entity_id in md.entity.keys(), "Entityid {0} not found in {1}".format(self.entity_id, ', '.join(md.entity.keys())) assert self.entity_id in md.entity.keys()
except KeyError: except KeyError:
if len(md.entity.keys()) == 1: if len(md.entity.keys()) == 1:
self.entity_id = md.entity.keys()[0] self.entity_id = md.entity.keys()[0]
@@ -296,34 +284,15 @@ class SAML2client(object):
self.setup() self.setup()
except (AttributeError, ToOld), err: except (AttributeError, ToOld), err:
print >> sys.stdout, "Configuration Error: %s" % err print >> sys.stdout, "Configuration Error: %s" % err
return
self.client = Saml2Client(self.sp_config)
conv = None
if self.args.pretty: if self.args.pretty:
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
else: else:
pp = None pp = None
conv = None
try:
self.client = Saml2Client(self.sp_config)
except Exception, err:
if conv:
self.test_log = conv.test_output
self.test_log.append(exception_trace("RUN", err))
else:
self.test_log = exception_trace("RUN", err)
tsum = self.test_summation(self.args.oper)
if pp:
pp.pprint(tsum)
else:
print >> sys.stdout, json.dumps(tsum, **JSON_DUMPS_ARGS)
if tsum["status"] > 1 or self.args.debug or err:
self.output_log(memoryhandler, streamhandler)
return
try: try:
try: try:
oper = self.operations.OPERATIONS[self.args.oper] oper = self.operations.OPERATIONS[self.args.oper]
@@ -369,7 +338,7 @@ class SAML2client(object):
if pp: if pp:
pp.pprint(tsum) pp.pprint(tsum)
else: else:
print >> sys.stdout, json.dumps(tsum, **JSON_DUMPS_ARGS) print >> sys.stdout, json.dumps(tsum)
if tsum["status"] > 1 or self.args.debug or err: if tsum["status"] > 1 or self.args.debug or err:
self.output_log(memoryhandler, streamhandler) self.output_log(memoryhandler, streamhandler)
@@ -416,7 +385,7 @@ class SAML2client(object):
lista.append(item) lista.append(item)
print json.dumps(lista, **JSON_DUMPS_ARGS) print json.dumps(lista)
def _get_operation(self, operation): def _get_operation(self, operation):
return self.operations.OPERATIONS[operation] return self.operations.OPERATIONS[operation]
@@ -430,7 +399,7 @@ class SAML2client(object):
mod = import_module("config") mod = import_module("config")
_res = dict([(key, cnf["description"]) for key, cnf in _res = dict([(key, cnf["description"]) for key, cnf in
mod.CONFIG.items()]) mod.CONFIG.items()])
print json.dumps(_res, **JSON_DUMPS_ARGS) print json.dumps(_res)
def verify_metadata(self): def verify_metadata(self):
self.json_config = self.json_config_file() self.json_config = self.json_config_file()

View File

@@ -5,16 +5,14 @@ import urllib
import cookielib import cookielib
from saml2 import BINDING_HTTP_REDIRECT, BINDING_URI from saml2 import BINDING_HTTP_REDIRECT, BINDING_URI
from saml2 import BINDING_HTTP_POST, BINDING_SOAP from saml2 import BINDING_HTTP_POST
from saml2 import httpbase from saml2 import BINDING_SOAP
from saml2.mdstore import REQ2SRV from saml2.mdstore import REQ2SRV
from saml2.pack import http_redirect_message from saml2.pack import http_redirect_message, http_form_post_message
from saml2.pack import http_form_post_message
from saml2.s_utils import rndstr from saml2.s_utils import rndstr
from saml2test import tool from saml2test import tool
from saml2test import OperationError
from saml2test import FatalError from saml2test import FatalError
__author__ = 'rohe0002' __author__ = 'rohe0002'
@@ -82,14 +80,7 @@ class Conversation(tool.Conversation):
response = None response = None
for srv in srvs: for srv in srvs:
try: response = self._send(srv)
response = self._send(srv)
except httpbase.ConnectionError, err:
logger.debug("IO error: %s" % err)
raise OperationError("IO error: %s" % err)
except Exception, err:
raise
if response is not None: if response is not None:
break break
@@ -105,7 +96,7 @@ class Conversation(tool.Conversation):
try: try:
req = self.oper.args["message"] req = self.oper.args["message"]
except KeyError: except KeyError:
req_id, req = self.qfunc(**self.qargs) req = self.qfunc(**self.qargs)
self.request = self.oper.pre_processing(req, self.args) self.request = self.oper.pre_processing(req, self.args)
str_req = "%s" % self.request str_req = "%s" % self.request
@@ -193,9 +184,9 @@ class Conversation(tool.Conversation):
# remove args the create function can't handle # remove args the create function can't handle
fargs = inspect.getargspec(self.qfunc).args fargs = inspect.getargspec(self.qfunc).args
if _oper._class: if _oper._class:
fargs.extend([p for p, _c, _r in fargs.extend([p for p, c, r in
_oper._class.c_attributes.values()]) _oper._class.c_attributes.values()])
fargs.extend([p for p, _c in _oper._class.c_children.values()]) fargs.extend([p for p, c in _oper._class.c_children.values()])
for arg in qargs.keys(): for arg in qargs.keys():
if arg not in fargs: if arg not in fargs:
del qargs[arg] del qargs[arg]
@@ -203,7 +194,7 @@ class Conversation(tool.Conversation):
self.qargs = qargs self.qargs = qargs
def my_endpoints(self): def my_endpoints(self):
return [e for e, _b in self.client.config.getattr("endpoints", "sp")[ return [e for e, b in self.client.config.getattr("endpoints", "sp")[
"assertion_consumer_service"]] "assertion_consumer_service"]]
def handle_result(self): def handle_result(self):

View File

@@ -19,13 +19,20 @@ from saml2.samlp import Response
from saml2.sigver import cert_from_key_info_dict from saml2.sigver import cert_from_key_info_dict
from saml2.sigver import key_from_key_value_dict from saml2.sigver import key_from_key_value_dict
# Import the status codes used indicate the test results
from saml2test.status import OK, CRITICAL, WARNING
from saml2.time_util import str_to_time from saml2.time_util import str_to_time
__author__ = 'rolandh' __author__ = 'rolandh'
INFORMATION = 0
OK = 1
WARNING = 2
ERROR = 3
CRITICAL = 4
INTERACTION = 5
STATUSCODE = ["INFORMATION", "OK", "WARNING", "ERROR", "CRITICAL",
"INTERACTION"]
PREFIX = "-----BEGIN CERTIFICATE-----" PREFIX = "-----BEGIN CERTIFICATE-----"
POSTFIX = "-----END CERTIFICATE-----" POSTFIX = "-----END CERTIFICATE-----"
@@ -56,8 +63,7 @@ class CheckSaml2IntMetaData(Check):
# contact person # contact person
if "contact_person" not in idpsso and "contact_person" not in ed: if "contact_person" not in idpsso and "contact_person" not in ed:
self._message = "Metadata should contain contact person " self._message = "Metadata should contain contact person information"
"information"
self._status = WARNING self._status = WARNING
return res return res
else: else:
@@ -251,15 +257,14 @@ class CheckSubjectNameIDFormat(Check):
""" """
The <NameIDPolicy> element tailors the name identifier in the subjects of The <NameIDPolicy> element tailors the name identifier in the subjects of
assertions resulting from an <AuthnRequest>. assertions resulting from an <AuthnRequest>.
When this element is used, if the content is not understood by or When this element is used, if the content is not understood by or acceptable
acceptable to the identity provider, then a <Response> message element MUST to the identity provider, then a <Response> message element MUST be
be returned with an error <Status>, and MAY contain a second-level returned with an error <Status>, and MAY contain a second-level
<StatusCode> of urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy. <StatusCode> of urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy.
If the Format value is omitted or set to If the Format value is omitted or set to urn:oasis:names:tc:SAML:2.0:nameid-
urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified, then the identity format:unspecified, then the identity provider is free to return any kind
provider is free to return any kind of identifier, subject to any of identifier, subject to any additional constraints due to the content of
additional constraints due to the content of this element or the policies this element or the policies of the identity provider or principal.
of the identity provider or principal.
""" """
cid = "check-saml2int-nameid-format" cid = "check-saml2int-nameid-format"
msg = "Attribute error" msg = "Attribute error"
@@ -460,7 +465,7 @@ class VerifyFunctionality(Check):
md = conv.client.metadata md = conv.client.metadata
entity = md[conv.entity_id] entity = md[conv.entity_id]
for desc in ["idpsso_descriptor", "attribute_authority_descriptor", for desc in ["idpsso_descriptor", "attribute_authority_descriptor",
"authn_authority_descriptor"]: "auth_authority_descriptor"]:
try: try:
srvgrps = entity[desc] srvgrps = entity[desc]
except KeyError: except KeyError:
@@ -497,8 +502,8 @@ class VerifyFunctionality(Check):
if self._status != OK: if self._status != OK:
return res return res
res = self._binding_support(conv, oper.request, res = self._binding_support(conv, oper.request, args["request_binding"],
args["request_binding"], "idpsso") "idpsso")
if self._status != OK: if self._status != OK:
return res return res
@@ -513,9 +518,7 @@ class VerifyFunctionality(Check):
pass pass
else: else:
res = self._nameid_format_support(conv, res = self._nameid_format_support(conv,
args[ args["name_id_policy"].format)
"name_id_policy"
].format)
return res return res
@@ -634,7 +637,7 @@ CLASS_CACHE = {}
def factory(cid, classes=CLASS_CACHE): def factory(cid, classes=CLASS_CACHE):
if len(classes) == 0: if len(classes) == 0:
check.factory(cid, classes) check.factory(cid, classes)
for _name, obj in inspect.getmembers(sys.modules[__name__]): for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj): if inspect.isclass(obj):
try: try:
classes[obj.cid] = obj classes[obj.cid] = obj

View File

@@ -1,5 +1,3 @@
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rohe0002' __author__ = 'rohe0002'
import json import json
@@ -14,7 +12,6 @@ from mechanize._form import ListControl
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def pick_interaction(interactions, _base="", content="", req=None): def pick_interaction(interactions, _base="", content="", req=None):
unic = content unic = content
if content: if content:
@@ -63,7 +60,7 @@ class FlowException(Exception):
self.url = url self.url = url
def __str__(self): def __str__(self):
return json.dumps(self.__dict__, **JSON_DUMPS_ARGS) return json.dumps(self.__dict__)
class RResponse(): class RResponse():
@@ -278,6 +275,7 @@ def select_form(httpc, orig_response, **kwargs):
return do_click(httpc, form, **kwargs) return do_click(httpc, form, **kwargs)
#noinspection PyUnusedLocal
def chose(httpc, orig_response, path, **kwargs): def chose(httpc, orig_response, path, **kwargs):
""" """
Sends a HTTP GET to a url given by the present url and the given Sends a HTTP GET to a url given by the present url and the given
@@ -289,6 +287,7 @@ def chose(httpc, orig_response, path, **kwargs):
:return: The response do_click() returns :return: The response do_click() returns
""" """
if not path.startswith("http"): if not path.startswith("http"):
try: try:
_url = orig_response.url _url = orig_response.url
@@ -325,6 +324,7 @@ def NoneFunc():
return None return None
#noinspection PyUnusedLocal
def parse(httpc, orig_response, **kwargs): def parse(httpc, orig_response, **kwargs):
# content is a form from which I get the SAMLResponse # content is a form from which I get the SAMLResponse
response = RResponse(orig_response) response = RResponse(orig_response)
@@ -338,6 +338,7 @@ def parse(httpc, orig_response, **kwargs):
"RelayState": form["RelayState"]} "RelayState": form["RelayState"]}
#noinspection PyUnusedLocal
def interaction(args): def interaction(args):
_type = args["type"] _type = args["type"]
if _type == "form": if _type == "form":

View File

@@ -6,7 +6,6 @@ __author__ = 'rolandh'
from idp_test.saml2base import AuthnRequest from idp_test.saml2base import AuthnRequest
class DummyExtension(SamlBase): class DummyExtension(SamlBase):
"""The urn:mace:umu.se:SAML:2.0:extension:foo element """ """The urn:mace:umu.se:SAML:2.0:extension:foo element """
@@ -18,14 +17,12 @@ class DummyExtension(SamlBase):
c_child_order = SamlBase.c_child_order[:] c_child_order = SamlBase.c_child_order[:]
c_cardinality = SamlBase.c_cardinality.copy() c_cardinality = SamlBase.c_cardinality.copy()
class AuthnRequest_UnknownIssuer(AuthnRequest): class AuthnRequest_UnknownIssuer(AuthnRequest):
def pre_processing(self, message, args): def pre_processing(self, message, args):
_issuer = message.issuer _issuer = message.issuer
_issuer.text = "https://www.example.com/foobar.xml" _issuer.text = "https://www.example.com/foobar.xml"
return message return message
class AuthnRequest_UnknownExtension(AuthnRequest): class AuthnRequest_UnknownExtension(AuthnRequest):
def pre_processing(self, message, args): def pre_processing(self, message, args):
message.extension = ExtensionContainer() message.extension = ExtensionContainer()

View File

@@ -1,9 +1,14 @@
from saml2 import samlp from saml2 import samlp
from saml2 import BINDING_HTTP_ARTIFACT, BINDING_HTTP_POST from saml2 import BINDING_HTTP_ARTIFACT
from saml2 import BINDING_HTTP_REDIRECT, BINDING_PAOS, BINDING_SOAP from saml2 import BINDING_HTTP_POST
from saml2 import BINDING_HTTP_REDIRECT
from saml2 import BINDING_PAOS
from saml2 import BINDING_SOAP
from saml2 import BINDING_URI from saml2 import BINDING_URI
from saml2.saml import NAMEID_FORMAT_PERSISTENT, NAMEID_FORMAT_UNSPECIFIED from saml2.saml import NAMEID_FORMAT_PERSISTENT
from saml2.saml import NAMEID_FORMAT_TRANSIENT, NAMEID_FORMAT_EMAILADDRESS from saml2.saml import NAMEID_FORMAT_UNSPECIFIED
from saml2.saml import NAMEID_FORMAT_TRANSIENT
from saml2.saml import NAMEID_FORMAT_EMAILADDRESS
from idp_test.check import CheckLogoutSupport from idp_test.check import CheckLogoutSupport
from idp_test.check import CheckSaml2IntAttributes from idp_test.check import CheckSaml2IntAttributes
@@ -366,7 +371,7 @@ OPERATIONS = {
"sequence": [AuthnRequest], "sequence": [AuthnRequest],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["verify"] "depend":["verify"]
}, },
'authn-nid_transient': { 'authn-nid_transient': {
"tc_id": "S2c-10", "tc_id": "S2c-10",
@@ -375,7 +380,7 @@ OPERATIONS = {
"sequence": [AuthnRequestNID_Transient], "sequence": [AuthnRequestNID_Transient],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-nid_email': { 'authn-nid_email': {
"tc_id": "S2c-20", "tc_id": "S2c-20",
@@ -384,7 +389,7 @@ OPERATIONS = {
"sequence": [AuthnRequestNID_Email], "sequence": [AuthnRequestNID_Email],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-nid_no': { 'authn-nid_no': {
"tc_id": "S2c-21", "tc_id": "S2c-21",
@@ -393,7 +398,7 @@ OPERATIONS = {
"sequence": [AuthnRequestNID_no], "sequence": [AuthnRequestNID_no],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-nid_unspecified': { 'authn-nid_unspecified': {
"tc_id": "S2c-21", "tc_id": "S2c-21",
@@ -402,7 +407,7 @@ OPERATIONS = {
"sequence": [AuthnRequestNID_Unspecified], "sequence": [AuthnRequestNID_Unspecified],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-post': { 'authn-post': {
"tc_id": "S2c-08", "tc_id": "S2c-08",
@@ -411,7 +416,7 @@ OPERATIONS = {
"sequence": [AuthnRequestPost], "sequence": [AuthnRequestPost],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-post-transient': { 'authn-post-transient': {
"tc_id": "S2c-09", "tc_id": "S2c-09",
@@ -420,48 +425,48 @@ OPERATIONS = {
"sequence": [AuthnRequestPostNID_Transient], "sequence": [AuthnRequestPostNID_Transient],
"tests": {"pre": [CheckSaml2IntMetaData], "tests": {"pre": [CheckSaml2IntMetaData],
"post": []}, "post": []},
"depend": ["authn-post"] "depend":["authn-post"]
}, },
'attribute-query': { 'attribute-query':{
"tc_id": "S2c-01", "tc_id": "S2c-01",
"name": "", "name": "",
"sequence": [AuthnRequest, AttributeQuery], "sequence":[AuthnRequest, AttributeQuery],
"depend": ["authn"] "depend":["authn"]
}, },
'attribute-query-transient': { 'attribute-query-transient':{
"tc_id": "S2c-20", "tc_id": "S2c-20",
"name": "", "name": "",
"sequence": [AuthnRequestNID_Transient, AttributeQuery], "sequence":[AuthnRequestNID_Transient, AttributeQuery],
"depend": ["authn"] "depend":["authn"]
}, },
'authn_endpoint_index': { 'authn_endpoint_index': {
"tc_id": "S2c-03", "tc_id": "S2c-03",
"name": '', "name": '',
"descr": '', "descr": '',
"sequence": [AuthnRequestEndpointIndex], "sequence": [AuthnRequestEndpointIndex],
"depend": ["authn"] "depend":["authn"]
}, },
'authn_endpoint_index-transient': { 'authn_endpoint_index-transient': {
"tc_id": "S2c-03", "tc_id": "S2c-03",
"name": '', "name": '',
"descr": '', "descr": '',
"sequence": [AuthnRequestEndpointIndexNIDTransient], "sequence": [AuthnRequestEndpointIndexNIDTransient],
"depend": ["authn"] "depend":["authn"]
}, },
'authn_specified_endpoint': { 'authn_specified_endpoint': {
"tc_id": "S2c-04", "tc_id": "S2c-04",
"name": '', "name": '',
"descr": '', "descr": '',
"sequence": [AuthnRequestSpecEndpoint], "sequence": [AuthnRequestSpecEndpoint],
"depend": ["authn"] "depend":["authn"]
}, },
'authn-artifact': { 'authn-artifact':{
'tc_id': "S2c-05", 'tc_id': "S2c-05",
"name": "SAML2 AuthnRequest using an artifact", "name": "SAML2 AuthnRequest using an artifact",
"descr": ('AuthnRequest using HTTP-redirect and artifact'), "descr": ('AuthnRequest using HTTP-redirect and artifact'),
"sequence": [AuthnRequest_using_Artifact] "sequence": [AuthnRequest_using_Artifact]
}, },
'authn-artifact_nid-transient': { 'authn-artifact_nid-transient':{
'tc_id': "S2c-05", 'tc_id': "S2c-05",
"name": "SAML2 AuthnRequest expecting artifact response", "name": "SAML2 AuthnRequest expecting artifact response",
"descr": ('AuthnRequest using HTTP-redirect and artifact'), "descr": ('AuthnRequest using HTTP-redirect and artifact'),
@@ -473,7 +478,7 @@ OPERATIONS = {
"descr": 'AuthnRequest followed by an AssertionIDRequest', "descr": 'AuthnRequest followed by an AssertionIDRequest',
"sequence": [AuthnRequest, AssertionIDRequest], "sequence": [AuthnRequest, AssertionIDRequest],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-nid_transient-assertion_id_request': { 'authn-nid_transient-assertion_id_request': {
"tc_id": "S2c-26", "tc_id": "S2c-26",
@@ -481,7 +486,7 @@ OPERATIONS = {
"descr": 'AuthnRequest followed by an AssertionIDRequest', "descr": 'AuthnRequest followed by an AssertionIDRequest',
"sequence": [AuthnRequestNID_Transient, AssertionIDRequest], "sequence": [AuthnRequestNID_Transient, AssertionIDRequest],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-with-name_id_policy': { 'authn-with-name_id_policy': {
"tc_id": "S2c-11", "tc_id": "S2c-11",
@@ -489,7 +494,7 @@ OPERATIONS = {
"descr": 'AuthnRequest with specific NameIDPolicy', "descr": 'AuthnRequest with specific NameIDPolicy',
"sequence": [AuthnRequest_NameIDPolicy1], "sequence": [AuthnRequest_NameIDPolicy1],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'authn-with-name_id_policy_nid-transient': { 'authn-with-name_id_policy_nid-transient': {
"tc_id": "S2c-31", "tc_id": "S2c-31",
@@ -497,13 +502,13 @@ OPERATIONS = {
"descr": 'AuthnRequest with specific NameIDPolicy', "descr": 'AuthnRequest with specific NameIDPolicy',
"sequence": [AuthnRequest_NameIDPolicy1Transient], "sequence": [AuthnRequest_NameIDPolicy1Transient],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'ecp_authn': { 'ecp_authn': {
'tc_id': "S2c-12", 'tc_id': "S2c-12",
"name": "SAML2 AuthnRequest using ECP and PAOS", "name": "SAML2 AuthnRequest using ECP and PAOS",
"descr": "SAML2 AuthnRequest using ECP and PAOS", "descr": "SAML2 AuthnRequest using ECP and PAOS",
"sequence": [ECP_AuthnRequest] "sequence":[ECP_AuthnRequest]
}, },
'log-in-out': { 'log-in-out': {
"tc_id": "S2c-13", "tc_id": "S2c-13",
@@ -511,31 +516,31 @@ OPERATIONS = {
"descr": 'AuthnRequest using HTTP-redirect followed by a logout', "descr": 'AuthnRequest using HTTP-redirect followed by a logout',
"sequence": [AuthnRequest, LogOutRequest], "sequence": [AuthnRequest, LogOutRequest],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
'manage_nameid': { 'manage_nameid':{
"tc_id": "S2c-14", "tc_id": "S2c-14",
"name": "Setting the SP provided ID by using ManageNameID", "name": "Setting the SP provided ID by using ManageNameID",
"sequence": [AuthnRequest, ManageNameIDRequest], "sequence":[AuthnRequest, ManageNameIDRequest],
"depend": ["authn"] "depend":["authn"]
}, },
'manage_nameid_nid-transient': { 'manage_nameid_nid-transient':{
"tc_id": "S2c-14", "tc_id": "S2c-14",
"name": "Setting the SP provided ID by using ManageNameID", "name": "Setting the SP provided ID by using ManageNameID",
"sequence": [AuthnRequestNID_Transient, ManageNameIDRequest], "sequence":[AuthnRequestNID_Transient, ManageNameIDRequest],
"depend": ["authn"] "depend":["authn"]
}, },
'nameid-mapping': { 'nameid-mapping':{
"tc_id": "S2c-15", "tc_id": "S2c-15",
"name": "Simple NameIDMapping request", "name": "Simple NameIDMapping request",
"sequence": [AuthnRequest, NameIDMappingRequest], "sequence":[AuthnRequest, NameIDMappingRequest],
"depend": ["authn"] "depend":["authn"]
}, },
'authn-authn_query': { 'authn-authn_query': {
"name": 'AuthnRequest and then an AuthnQuery', "name": 'AuthnRequest and then an AuthnQuery',
"descr": 'AuthnRequest followed by an AuthnQuery', "descr": 'AuthnRequest followed by an AuthnQuery',
"sequence": [AuthnRequest, AuthnQuery], "sequence": [AuthnRequest, AuthnQuery],
"tests": {"pre": [CheckSaml2IntMetaData], "post": []}, "tests": {"pre": [CheckSaml2IntMetaData], "post": []},
"depend": ["authn"] "depend":["authn"]
}, },
} }

View File

@@ -12,8 +12,6 @@ logger = logging.getLogger(__name__)
__author__ = 'rolandh' __author__ = 'rolandh'
JSON_DUMPS_ARGS = {"indent": 4, "sort_keys": True}
class FatalError(Exception): class FatalError(Exception):
pass pass
@@ -23,7 +21,7 @@ class CheckError(Exception):
pass pass
class HttpError(Exception): class HTTP_ERROR(Exception):
pass pass
@@ -40,15 +38,11 @@ class ContextFilter(logging.Filter):
This is a filter which injects time laps information into the log. This is a filter which injects time laps information into the log.
""" """
def __init__(self, name=""):
logging.Filter.__init__(self, name)
self._start = 0
def start(self): def start(self):
self._start = time.time() self.start = time.time()
def filter(self, record): def filter(self, record):
record.delta = time.time() - self._start record.delta = time.time() - self.start
return True return True
@@ -64,7 +58,7 @@ def stop_script_by_name(name):
import os import os
p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE) p = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE)
out, _err = p.communicate() out, err = p.communicate()
for line in out.splitlines(): for line in out.splitlines():
if name in line: if name in line:
@@ -84,7 +78,7 @@ def get_page(url):
if resp.status_code == 200: if resp.status_code == 200:
return resp.text return resp.text
else: else:
raise HttpError(resp.status) raise HTTP_ERROR(resp.status)
def exception_trace(tag, exc, log=None): def exception_trace(tag, exc, log=None):

View File

@@ -1,13 +1,21 @@
import inspect import inspect
import json import json
import traceback
import sys
# Import the status codes used indicate the test results
from saml2test.status import INFORMATION, OK, ERROR, CRITICAL
__author__ = 'rolandh' __author__ = 'rolandh'
import traceback
import sys
INFORMATION = 0
OK = 1
WARNING = 2
ERROR = 3
CRITICAL = 4
INTERACTION = 5
STATUSCODE = ["INFORMATION", "OK", "WARNING", "ERROR", "CRITICAL",
"INTERACTION"]
CONT_JSON = "application/json" CONT_JSON = "application/json"
CONT_JWT = "application/jwt" CONT_JWT = "application/jwt"
@@ -145,7 +153,7 @@ class VerifyError(Error):
except Exception: except Exception:
pass pass
item, _msg = conv.protocol_response[-1] item, msg = conv.protocol_response[-1]
try: try:
assert item.type().endswith("ErrorResponse") assert item.type().endswith("ErrorResponse")
except AssertionError: except AssertionError:
@@ -239,10 +247,9 @@ class Parse(CriticalError):
return {} return {}
def factory(cid, classes): def factory(cid, classes):
if len(classes) == 0: if len(classes) == 0:
for _name, obj in inspect.getmembers(sys.modules[__name__]): for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj): if inspect.isclass(obj):
try: try:
classes[obj.cid] = obj classes[obj.cid] = obj

View File

@@ -1,5 +1,3 @@
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rohe0002' __author__ = 'rohe0002'
import json import json
@@ -25,7 +23,7 @@ class FlowException(Exception):
self.url = url self.url = url
def __str__(self): def __str__(self):
return json.dumps(self.__dict__, **JSON_DUMPS_ARGS) return json.dumps(self.__dict__)
class InteractionNeeded(Exception): class InteractionNeeded(Exception):
@@ -389,8 +387,7 @@ class Action(object):
except (KeyError, AttributeError): except (KeyError, AttributeError):
_args = {} _args = {}
_args.update({"location": location, "features": features, _args.update({"location": location, "features": features, "conv": conv})
"conv": conv})
logger.info("<-- FUNCTION: %s" % function.__name__) logger.info("<-- FUNCTION: %s" % function.__name__)
logger.info("<-- ARGS: %s" % _args) logger.info("<-- ARGS: %s" % _args)

View File

@@ -6,8 +6,6 @@ from urlparse import urlparse
from mechanize import ParseResponseEx from mechanize import ParseResponseEx
from mechanize._form import ControlNotFoundError, AmbiguityError from mechanize._form import ControlNotFoundError, AmbiguityError
from mechanize._form import ListControl from mechanize._form import ListControl
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rohe0002' __author__ = 'rohe0002'
@@ -22,7 +20,7 @@ class FlowException(Exception):
self.url = url self.url = url
def __str__(self): def __str__(self):
return json.dumps(self.__dict__, **JSON_DUMPS_ARGS) return json.dumps(self.__dict__)
class DResponse(): class DResponse():

View File

@@ -7,7 +7,7 @@ from urlparse import parse_qs
from saml2test.opfunc import Operation from saml2test.opfunc import Operation
from saml2test import FatalError from saml2test import FatalError
from saml2test.check import ExpectedError, ERROR from saml2test.check import ExpectedError, ERROR
from saml2test.status import INTERACTION from saml2test.check import INTERACTION
from saml2test.interaction import Interaction from saml2test.interaction import Interaction
from saml2test.interaction import Action from saml2test.interaction import Action
from saml2test.interaction import InteractionNeeded from saml2test.interaction import InteractionNeeded
@@ -61,7 +61,7 @@ class Conversation(object):
except KeyError: except KeyError:
pass pass
raise OperationError raise FatalError
def do_check(self, test, **kwargs): def do_check(self, test, **kwargs):
if isinstance(test, basestring): if isinstance(test, basestring):
@@ -128,7 +128,7 @@ class Conversation(object):
self.client.cookiejar = self.cjar["rp"] self.client.cookiejar = self.cjar["rp"]
for_me = True for_me = True
try: try:
_base, query = url.split("?") base, query = url.split("?")
except ValueError: except ValueError:
pass pass
else: else:
@@ -300,8 +300,8 @@ class Conversation(object):
break break
except (FatalError, OperationError): except (FatalError, OperationError):
raise raise
except Exception, _err: except Exception, err:
#self.err_check("exception", _err) #self.err_check("exception", err)
raise raise
try: try:

View File

@@ -13,18 +13,16 @@ from saml2.server import Server
from saml2.config import IdPConfig from saml2.config import IdPConfig
from saml2.config import logging from saml2.config import logging
from base import Conversation from sp_test.base import Conversation
from saml2test import FatalError from saml2test import FatalError
from saml2test import CheckError from saml2test import CheckError
from saml2test import ContextFilter from saml2test import ContextFilter
from saml2test import exception_trace from saml2test import exception_trace
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rolandh' __author__ = 'rolandh'
#formatter = #formatter = logging.Formatter("%(asctime)s %(name)s:%(levelname)s %(message)s")
# logging.Formatter("%(asctime)s %(name)s:%(levelname)s %(message)s")
formatter_2 = logging.Formatter( formatter_2 = logging.Formatter(
"%(delta).6f - %(levelname)s - [%(name)s] %(message)s") "%(delta).6f - %(levelname)s - [%(name)s] %(message)s")
@@ -40,87 +38,44 @@ memoryhandler.addFilter(cf)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
logger.addHandler(memoryhandler) logger.addHandler(memoryhandler)
# The streamhandler variable should be added to the logger if
# you want to see the log messages as they are printed instead
# of afterwards (mostly useful during debugging
#logger.addHandler(streamhandler)
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
class Client(object): class Client(object):
""" def __init__(self, operations, check_factory):
This is the SP testing client for saml2test. It contains the methods that self.operations = operations
are required to set up and run the tests you request. self.tests = None
"""
def __init__(self, check_factory):
"""
Creates a new SP testing client.
@param self: this SP testing client
@param check_factory: the factory containing the checks that are needed
during the SP test
"""
self.testsuite = None
self.check_factory = check_factory self.check_factory = check_factory
self._parser = argparse.ArgumentParser() self._parser = argparse.ArgumentParser()
self._parser.add_argument("-c", self._parser.add_argument("-c", dest="config", default="config",
dest="config",
default="config",
help="Configuration file for the IdP") help="Configuration file for the IdP")
self._parser.add_argument('-C', self._parser.add_argument(
dest="ca_certs", '-C', dest="ca_certs",
help="CA certs to use to verify HTTPS " help=("CA certs to use to verify HTTPS server certificates, ",
"server certificates, if HTTPS is used and " "if HTTPS is used and no server CA certs are defined then ",
"no server CA certs are defined then no " "no cert verification will be done"))
"cert verification will be done") self._parser.add_argument('-d', dest='debug', action='store_true',
self._parser.add_argument('-d',
dest='debug',
action='store_true',
help="Print debug information") help="Print debug information")
self._parser.add_argument("-H", self._parser.add_argument("-H", dest="pretty", action='store_true')
dest="pretty", self._parser.add_argument("-i", dest="insecure", action='store_true')
action='store_true', self._parser.add_argument('-J', dest="json_config_file",
help="Human readable status output")
self._parser.add_argument("-i",
dest="insecure",
action='store_true',
help="do not verify TLS certificates")
self._parser.add_argument('-J',
dest="json_config_file",
help="Script configuration") help="Script configuration")
self._parser.add_argument("-l", self._parser.add_argument(
dest="list", "-l", dest="list", action="store_true",
action="store_true", help="List all the test flows as a JSON object")
help="List all the test flows as a JSON " self._parser.add_argument('-m', dest="metadata", action='store_true',
"object")
self._parser.add_argument('-m',
dest="metadata",
action='store_true',
help="Return the IdP metadata") help="Return the IdP metadata")
self._parser.add_argument("-P", self._parser.add_argument(
dest="configpath", "-P", dest="configpath", default=".",
default=".", help="Path to the configuration file for the IdP")
help="Path to the configuration file for " self._parser.add_argument("-t", dest="testpackage",
"the IdP") help="Module describing tests")
self._parser.add_argument("-t", self._parser.add_argument('-v', dest='verbose', action='store_true',
dest="testsuite",
default="basicTests",
help="Specifies the test suite from which "
"you wish to run tests")
self._parser.add_argument('-v',
dest='verbose',
action='store_true',
help="Print runtime information") help="Print runtime information")
self._parser.add_argument("-Y", self._parser.add_argument("-Y", dest="pysamllog", action='store_true',
dest="pysamllog",
action='store_true',
help="Print PySAML2 logs") help="Print PySAML2 logs")
self._parser.add_argument("oper", self._parser.add_argument("oper", nargs="?", help="Which test to run")
nargs="?",
help="Which test to run")
self.interactions = None self.interactions = None
self.entity_id = None self.entity_id = None
@@ -188,9 +143,6 @@ class Client(object):
root_logger.addHandler(memoryhandler) root_logger.addHandler(memoryhandler)
root_logger.setLevel(logging.DEBUG) root_logger.setLevel(logging.DEBUG)
self.testsuite = import_module("sp_test.test_suites.%s" %
self.args.testsuite)
if self.args.metadata: if self.args.metadata:
return self.make_meta() return self.make_meta()
elif self.args.list: elif self.args.list:
@@ -205,15 +157,18 @@ class Client(object):
self.setup() self.setup()
if self.testsuite: try:
try: oper = self.operations.OPERATIONS[self.args.oper]
oper = self.testsuite.testcases[self.args.oper] except KeyError:
except ValueError: if self.tests:
try:
oper = self.tests.OPERATIONS[self.args.oper]
except ValueError:
print >> sys.stderr, "Undefined testcase"
return
else:
print >> sys.stderr, "Undefined testcase" print >> sys.stderr, "Undefined testcase"
return return
else:
print >> sys.stderr, "Undefined testcase"
return
opers = oper["sequence"] opers = oper["sequence"]
@@ -254,7 +209,7 @@ class Client(object):
if pp: if pp:
pp.pprint(tsum) pp.pprint(tsum)
else: else:
print >> sys.stdout, json.dumps(tsum, **JSON_DUMPS_ARGS) print >> sys.stdout, json.dumps(tsum)
if tsum["status"] > 1 or self.args.debug or err: if tsum["status"] > 1 or self.args.debug or err:
self.output_log(memoryhandler, streamhandler) self.output_log(memoryhandler, streamhandler)
@@ -280,10 +235,14 @@ class Client(object):
self.idp.metadata = metadata self.idp.metadata = metadata
#self.idp_config.metadata = metadata #self.idp_config.metadata = metadata
if self.args.testpackage:
self.tests = import_module("sp_test.package.%s" %
self.args.testpackage)
try: try:
self.entity_id = _jc["entity_id"] self.entity_id = _jc["entity_id"]
# Verify its the correct metadata # Verify its the correct metadata
assert self.entity_id in md.entity.keys(), "Entityid {0} not found in {1}".format(self.entity_id, ', '.join(md.entity.keys())) assert self.entity_id in md.entity.keys()
except KeyError: except KeyError:
if len(md.entity.keys()) == 1: if len(md.entity.keys()) == 1:
self.entity_id = md.entity.keys()[0] self.entity_id = md.entity.keys()[0]
@@ -300,10 +259,10 @@ class Client(object):
def list_operations(self): def list_operations(self):
res = [] res = []
for key, val in self.testsuite.testcases.items(): for key, val in self.operations.OPERATIONS.items():
res.append({"id": key, "name": val["name"]}) res.append({"id": key, "name": val["name"]})
print json.dumps(res, **JSON_DUMPS_ARGS) print json.dumps(res)
def verify_metadata(self): def verify_metadata(self):
pass pass

View File

@@ -14,11 +14,14 @@ from saml2.sigver import signed_instance_factory, pre_signature_part
from saml2test import CheckError, FatalError from saml2test import CheckError, FatalError
from saml2test.check import Check from saml2test.check import Check
from saml2test.check import ExpectedError from saml2test.check import ExpectedError
from saml2test.status import INTERACTION, STATUSCODE from saml2test.check import INTERACTION
from saml2test.check import STATUSCODE
from saml2test.interaction import Action from saml2test.interaction import Action
from saml2test.interaction import Interaction from saml2test.interaction import Interaction
from saml2test.interaction import InteractionNeeded from saml2test.interaction import InteractionNeeded
from sp_test.tests import ErrorResponse
__author__ = 'rolandh' __author__ = 'rolandh'
import logging import logging
@@ -119,8 +122,8 @@ class Conversation():
for serv in ["aa", "aq", "idp"]: for serv in ["aa", "aq", "idp"]:
endpoints = self._config.getattr("endpoints", serv) endpoints = self._config.getattr("endpoints", serv)
if endpoints: if endpoints:
for _typ, spec in endpoints.items(): for typ, spec in endpoints.items():
for url, _binding in spec: for url, binding in spec:
yield url yield url
def which_endpoint(self, url): def which_endpoint(self, url):
@@ -165,11 +168,11 @@ class Conversation():
_txt = self.last_response.content _txt = self.last_response.content
if self.last_response.status_code >= 400: if self.last_response.status_code >= 400:
raise FatalError("Unexpected error") raise FatalError("Did not expected error")
def handle_redirect(self): def handle_redirect(self):
try: try:
_url, query = self.last_response.headers["location"].split("?") url, query = self.last_response.headers["location"].split("?")
except KeyError: except KeyError:
return return
@@ -250,7 +253,7 @@ class Conversation():
if param in self.json_config: if param in self.json_config:
args[param] = self.json_config[param] args[param] = self.json_config[param]
if getattr(resp, "_send_error", False) == True: if resp == ErrorResponse:
func = getattr(self.instance, "create_error_response") func = getattr(self.instance, "create_error_response")
else: else:
_op = camel2underscore.sub(r'_\1', req._class.c_tag).lower() _op = camel2underscore.sub(r'_\1', req._class.c_tag).lower()
@@ -312,27 +315,13 @@ class Conversation():
Un-solicited starts with the IDP sending something. Un-solicited starts with the IDP sending something.
""" """
if len(flow) >= 3: if len(flow) >= 3:
logger.info("TEST FLOW: Start by GET-ing the page")
self.wb_send() self.wb_send()
logger.info("TEST FLOW: Continuing with: %s" % flow[0].__name__)
self.intermit(flow[0]._interaction) self.intermit(flow[0]._interaction)
logger.info("TEST FLOW: Handling redirect")
self.handle_redirect() self.handle_redirect()
logger.info("TEST FLOW: Sending IdP Response with expected request"
" %s and response to be used %s" %
(flow[1].__name__, flow[2].__name__))
self.send_idp_response(flow[1], flow[2]) self.send_idp_response(flow[1], flow[2])
if len(flow) == 4: if len(flow) == 4:
if flow[3] is None:
flowName = "None"
else:
flowName = flow[3].__name__
logger.info("TEST FLOW Handling result with HTTP Response check"
" for %s" % flowName)
self.handle_result(flow[3]) self.handle_result(flow[3])
else: else:
logger.info("TEST FLOW: Handling result (without HTTP Response "
"check)")
self.handle_result() self.handle_result()
def do_sequence(self, oper, tests=None): def do_sequence(self, oper, tests=None):

View File

@@ -1,8 +1,8 @@
import inspect import inspect
import sys import sys
# Import the status codes used indicate the test results
from saml2test.status import CRITICAL
from saml2test.check import Check from saml2test.check import Check
from saml2test.check import CRITICAL
from saml2test import check from saml2test import check
from saml2test.interaction import Interaction from saml2test.interaction import Interaction
@@ -45,6 +45,8 @@ class ErrorResponse(Check):
self._status = CRITICAL self._status = CRITICAL
return {} return {}
# =============================================================================
CLASS_CACHE = {} CLASS_CACHE = {}
@@ -52,7 +54,7 @@ CLASS_CACHE = {}
def factory(cid, classes=CLASS_CACHE): def factory(cid, classes=CLASS_CACHE):
if len(classes) == 0: if len(classes) == 0:
check.factory(cid, classes) check.factory(cid, classes)
for _name, obj in inspect.getmembers(sys.modules[__name__]): for name, obj in inspect.getmembers(sys.modules[__name__]):
if inspect.isclass(obj): if inspect.isclass(obj):
try: try:
classes[obj.cid] = obj classes[obj.cid] = obj

View File

@@ -1 +0,0 @@
# Group of test suites

View File

@@ -1,21 +1,16 @@
# -*- coding: utf-8 -*-
import copy import copy
from saml2 import samlp from saml2 import samlp, SamlBase
from saml2 import NAMEID_FORMAT_EMAILADDRESS from saml2 import NAMEID_FORMAT_EMAILADDRESS
from saml2 import BINDING_HTTP_REDIRECT from saml2 import BINDING_HTTP_REDIRECT
from saml2 import BINDING_HTTP_POST from saml2 import BINDING_HTTP_POST
from saml2.s_utils import rndstr from saml2.s_utils import rndstr
from saml2.saml import SCM_BEARER from saml2.saml import SCM_BEARER, Condition, XSI_TYPE, Audience
from saml2.saml import Condition
from saml2.saml import XSI_TYPE
from saml2.saml import Audience
from saml2.saml import NAMEID_FORMAT_PERSISTENT from saml2.saml import NAMEID_FORMAT_PERSISTENT
from saml2.saml import SCM_SENDER_VOUCHES from saml2.saml import SCM_SENDER_VOUCHES
from saml2.saml import ConditionAbstractType_ from saml2.saml import ConditionAbstractType_
from saml2.samlp import STATUS_AUTHN_FAILED from saml2.samlp import STATUS_AUTHN_FAILED
from saml2.time_util import in_a_while from saml2.time_util import in_a_while, a_while_ago
from saml2.time_util import a_while_ago
from sp_test.check import VerifyContent from sp_test.check import VerifyContent
from sp_test import check from sp_test import check
from saml2test import ip_addresses from saml2test import ip_addresses
@@ -40,10 +35,10 @@ class TimeRestriction(ConditionAbstractType_):
c_tag = 'TimeRestriction' c_tag = 'TimeRestriction'
c_namespace = "urn:mace:umu.se:sso" c_namespace = "urn:mace:umu.se:sso"
c_children = copy.copy(ConditionAbstractType_.c_children) c_children = ConditionAbstractType_.c_children.copy()
c_attributes = copy.copy(ConditionAbstractType_.c_attributes) c_attributes = ConditionAbstractType_.c_attributes.copy()
c_child_order = ConditionAbstractType_.c_child_order[:] c_child_order = ConditionAbstractType_.c_child_order[:]
c_cardinality = copy.copy(ConditionAbstractType_.c_cardinality) c_cardinality = ConditionAbstractType_.c_cardinality.copy()
c_attributes['StartTime'] = ('start_time', 'time', False) c_attributes['StartTime'] = ('start_time', 'time', False)
c_attributes['EndTime'] = ('end_time', 'time', False) c_attributes['EndTime'] = ('end_time', 'time', False)
@@ -116,7 +111,6 @@ class ErrorResponse(Response):
"info": (STATUS_AUTHN_FAILED, "Unknown user") "info": (STATUS_AUTHN_FAILED, "Unknown user")
} }
_binding = BINDING_HTTP_POST _binding = BINDING_HTTP_POST
_send_error = True
class LogoutResponse(Response): class LogoutResponse(Response):
@@ -157,7 +151,7 @@ class AuthnResponse_NameIDformat_foo(AuthnResponse):
class AuthnResponse_without_SubjectConfirmationData_1(AuthnResponse): class AuthnResponse_without_SubjectConfirmationData_1(AuthnResponse):
def pre_processing(self, message, **kwargs): def pre_processing(self, message, **kwargs):
_confirmation = message.assertion.subject.subject_confirmation[0] _confirmation = message.assertion.subject.subject_confirmation
_confirmation.subject_confirmation_data = None _confirmation.subject_confirmation_data = None
_confirmation.method = SCM_SENDER_VOUCHES _confirmation.method = SCM_SENDER_VOUCHES
return message return message
@@ -177,11 +171,9 @@ class AuthnResponse_rnd_Response_inresponseto(AuthnResponse):
return message return message
class AuthnResponse_rnd_SubjectConfirmationData_inresponseto(AuthnResponse): class AuthnResponse_rnd_Response_assertion_inresponseto(AuthnResponse):
def pre_processing(self, message, **kwargs): def pre_processing(self, message, **kwargs):
_scs = message.assertion.subject.subject_confirmation message.assertion.in_response_to = rndstr(16)
for _sc in _scs:
_sc.subject_confirmation_data.in_response_to = rndstr(16)
return message return message
@@ -206,6 +198,13 @@ class AuthnResponse_missing_Recipient(AuthnResponse):
return message return message
class AuthnResponse_missing_Recipient(AuthnResponse):
def pre_processing(self, message, **kwargs):
_confirmation = message.assertion.subject.subject_confirmation
_confirmation[0].subject_confirmation_data.recipient = None
return message
class AuthnResponse_broken_destination(AuthnResponse): class AuthnResponse_broken_destination(AuthnResponse):
def pre_processing(self, message, **kwargs): def pre_processing(self, message, **kwargs):
message.destination = "NotAUrl" message.destination = "NotAUrl"
@@ -359,7 +358,12 @@ class AuthnResponse_AudienceRestriction_appended_audience(AuthnResponse):
conditions.audience_restriction[0].audience.append(extra) conditions.audience_restriction[0].audience.append(extra)
return message return message
testcases = {
PHASES = {
"login_redirect": (Login, AuthnRequest, AuthnResponse_redirect),
}
OPERATIONS = {
'sp-00': { 'sp-00': {
"name": 'Basic Login test', "name": 'Basic Login test',
"descr": 'Basic Login test', "descr": 'Basic Login test',
@@ -375,8 +379,7 @@ testcases = {
'FL03': { 'FL03': {
"name": """SP should not accept a Response as valid, when the "name": """SP should not accept a Response as valid, when the
StatusCode is not success""", StatusCode is not success""",
"sequence": [(Login, AuthnRequest, ErrorResponse, "sequence": [(Login, AuthnRequest, ErrorResponse, check.ErrorResponse)],
check.ErrorResponse)],
"tests": {"pre": [], "post": []} "tests": {"pre": [], "post": []}
}, },
'FL04': { 'FL04': {
@@ -417,7 +420,7 @@ StatusCode is not success""",
"name": ("SP should not accept an assertion InResponseTo ", "name": ("SP should not accept an assertion InResponseTo ",
"which is chosen randomly"), "which is chosen randomly"),
"sequence": [(Login, AuthnRequest, "sequence": [(Login, AuthnRequest,
AuthnResponse_rnd_SubjectConfirmationData_inresponseto, AuthnResponse_rnd_Response_assertion_inresponseto,
check.ErrorResponse)], check.ErrorResponse)],
"tests": {"pre": [], "post": []} "tests": {"pre": [], "post": []}
}, },
@@ -516,8 +519,8 @@ StatusCode is not success""",
"tests": {"pre": [], "post": []} "tests": {"pre": [], "post": []}
}, },
'FL29': { 'FL29': {
"name": "Reject a Response with a " "name": "Reject a Response with a SubjectConfirmationData@NotOnOrAfter "
"SubjectConfirmationData@NotOnOrAfter in the past", "in the past",
"sequence": [(Login, AuthnRequest, "sequence": [(Login, AuthnRequest,
AuthnResponse_past_SubjectConfirmationData_NotOnOrAfter, AuthnResponse_past_SubjectConfirmationData_NotOnOrAfter,
check.ErrorResponse)], check.ErrorResponse)],

View File

@@ -12,230 +12,230 @@ SCHAC = "urn:oid:1.3.6.1.4.1.25178.2."
MAP = { MAP = {
"identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", "identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
"fro": { "fro": {
EDUPERSON_OID + '2': 'eduPersonNickname', EDUPERSON_OID+'2': 'eduPersonNickname',
EDUPERSON_OID + '9': 'eduPersonScopedAffiliation', EDUPERSON_OID+'9': 'eduPersonScopedAffiliation',
EDUPERSON_OID + '11': 'eduPersonAssurance', EDUPERSON_OID+'11': 'eduPersonAssurance',
EDUPERSON_OID + '10': 'eduPersonTargetedID', EDUPERSON_OID+'10': 'eduPersonTargetedID',
EDUPERSON_OID + '4': 'eduPersonOrgUnitDN', EDUPERSON_OID+'4': 'eduPersonOrgUnitDN',
NOREDUPERSON_OID + '6': 'norEduOrgAcronym', NOREDUPERSON_OID+'6': 'norEduOrgAcronym',
NOREDUPERSON_OID + '7': 'norEduOrgUniqueIdentifier', NOREDUPERSON_OID+'7': 'norEduOrgUniqueIdentifier',
NOREDUPERSON_OID + '4': 'norEduPersonLIN', NOREDUPERSON_OID+'4': 'norEduPersonLIN',
EDUPERSON_OID + '1': 'eduPersonAffiliation', EDUPERSON_OID+'1': 'eduPersonAffiliation',
NOREDUPERSON_OID + '2': 'norEduOrgUnitUniqueNumber', NOREDUPERSON_OID+'2': 'norEduOrgUnitUniqueNumber',
NETSCAPE_LDAP + '40': 'userSMIMECertificate', NETSCAPE_LDAP+'40': 'userSMIMECertificate',
NOREDUPERSON_OID + '1': 'norEduOrgUniqueNumber', NOREDUPERSON_OID+'1': 'norEduOrgUniqueNumber',
NETSCAPE_LDAP + '241': 'displayName', NETSCAPE_LDAP+'241': 'displayName',
UCL_DIR_PILOT + '37': 'associatedDomain', UCL_DIR_PILOT+'37': 'associatedDomain',
EDUPERSON_OID + '6': 'eduPersonPrincipalName', EDUPERSON_OID+'6': 'eduPersonPrincipalName',
NOREDUPERSON_OID + '8': 'norEduOrgUnitUniqueIdentifier', NOREDUPERSON_OID+'8': 'norEduOrgUnitUniqueIdentifier',
NOREDUPERSON_OID + '9': 'federationFeideSchemaVersion', NOREDUPERSON_OID+'9': 'federationFeideSchemaVersion',
X500ATTR_OID + '53': 'deltaRevocationList', X500ATTR_OID+'53': 'deltaRevocationList',
X500ATTR_OID + '52': 'supportedAlgorithms', X500ATTR_OID+'52': 'supportedAlgorithms',
X500ATTR_OID + '51': 'houseIdentifier', X500ATTR_OID+'51': 'houseIdentifier',
X500ATTR_OID + '50': 'uniqueMember', X500ATTR_OID+'50': 'uniqueMember',
X500ATTR_OID + '19': 'physicalDeliveryOfficeName', X500ATTR_OID+'19': 'physicalDeliveryOfficeName',
X500ATTR_OID + '18': 'postOfficeBox', X500ATTR_OID+'18': 'postOfficeBox',
X500ATTR_OID + '17': 'postalCode', X500ATTR_OID+'17': 'postalCode',
X500ATTR_OID + '16': 'postalAddress', X500ATTR_OID+'16': 'postalAddress',
X500ATTR_OID + '15': 'businessCategory', X500ATTR_OID+'15': 'businessCategory',
X500ATTR_OID + '14': 'searchGuide', X500ATTR_OID+'14': 'searchGuide',
EDUPERSON_OID + '5': 'eduPersonPrimaryAffiliation', EDUPERSON_OID+'5': 'eduPersonPrimaryAffiliation',
X500ATTR_OID + '12': 'title', X500ATTR_OID+'12': 'title',
X500ATTR_OID + '11': 'ou', X500ATTR_OID+'11': 'ou',
X500ATTR_OID + '10': 'o', X500ATTR_OID+'10': 'o',
X500ATTR_OID + '37': 'cACertificate', X500ATTR_OID+'37': 'cACertificate',
X500ATTR_OID + '36': 'userCertificate', X500ATTR_OID+'36': 'userCertificate',
X500ATTR_OID + '31': 'member', X500ATTR_OID+'31': 'member',
X500ATTR_OID + '30': 'supportedApplicationContext', X500ATTR_OID+'30': 'supportedApplicationContext',
X500ATTR_OID + '33': 'roleOccupant', X500ATTR_OID+'33': 'roleOccupant',
X500ATTR_OID + '32': 'owner', X500ATTR_OID+'32': 'owner',
NETSCAPE_LDAP + '1': 'carLicense', NETSCAPE_LDAP+'1': 'carLicense',
PKCS_9 + '1': 'email', PKCS_9+'1': 'email',
NETSCAPE_LDAP + '3': 'employeeNumber', NETSCAPE_LDAP+'3': 'employeeNumber',
NETSCAPE_LDAP + '2': 'departmentNumber', NETSCAPE_LDAP+'2': 'departmentNumber',
X500ATTR_OID + '39': 'certificateRevocationList', X500ATTR_OID+'39': 'certificateRevocationList',
X500ATTR_OID + '38': 'authorityRevocationList', X500ATTR_OID+'38': 'authorityRevocationList',
NETSCAPE_LDAP + '216': 'userPKCS12', NETSCAPE_LDAP+'216': 'userPKCS12',
EDUPERSON_OID + '8': 'eduPersonPrimaryOrgUnitDN', EDUPERSON_OID+'8': 'eduPersonPrimaryOrgUnitDN',
X500ATTR_OID + '9': 'street', X500ATTR_OID+'9': 'street',
X500ATTR_OID + '8': 'st', X500ATTR_OID+'8': 'st',
NETSCAPE_LDAP + '39': 'preferredLanguage', NETSCAPE_LDAP+'39': 'preferredLanguage',
EDUPERSON_OID + '7': 'eduPersonEntitlement', EDUPERSON_OID+'7': 'eduPersonEntitlement',
X500ATTR_OID + '2': 'knowledgeInformation', X500ATTR_OID+'2': 'knowledgeInformation',
X500ATTR_OID + '7': 'l', X500ATTR_OID+'7': 'l',
X500ATTR_OID + '6': 'c', X500ATTR_OID+'6': 'c',
X500ATTR_OID + '5': 'serialNumber', X500ATTR_OID+'5': 'serialNumber',
X500ATTR_OID + '4': 'sn', X500ATTR_OID+'4': 'sn',
UCL_DIR_PILOT + '60': 'jpegPhoto', UCL_DIR_PILOT+'60': 'jpegPhoto',
X500ATTR_OID + '65': 'pseudonym', X500ATTR_OID+'65': 'pseudonym',
NOREDUPERSON_OID + '5': 'norEduPersonNIN', NOREDUPERSON_OID+'5': 'norEduPersonNIN',
UCL_DIR_PILOT + '3': 'mail', UCL_DIR_PILOT+'3': 'mail',
UCL_DIR_PILOT + '25': 'dc', UCL_DIR_PILOT+'25': 'dc',
X500ATTR_OID + '40': 'crossCertificatePair', X500ATTR_OID+'40': 'crossCertificatePair',
X500ATTR_OID + '42': 'givenName', X500ATTR_OID+'42': 'givenName',
X500ATTR_OID + '43': 'initials', X500ATTR_OID+'43': 'initials',
X500ATTR_OID + '44': 'generationQualifier', X500ATTR_OID+'44': 'generationQualifier',
X500ATTR_OID + '45': 'x500UniqueIdentifier', X500ATTR_OID+'45': 'x500UniqueIdentifier',
X500ATTR_OID + '46': 'dnQualifier', X500ATTR_OID+'46': 'dnQualifier',
X500ATTR_OID + '47': 'enhancedSearchGuide', X500ATTR_OID+'47': 'enhancedSearchGuide',
X500ATTR_OID + '48': 'protocolInformation', X500ATTR_OID+'48': 'protocolInformation',
X500ATTR_OID + '54': 'dmdName', X500ATTR_OID+'54': 'dmdName',
NETSCAPE_LDAP + '4': 'employeeType', NETSCAPE_LDAP+'4': 'employeeType',
X500ATTR_OID + '22': 'teletexTerminalIdentifier', X500ATTR_OID+'22': 'teletexTerminalIdentifier',
X500ATTR_OID + '23': 'facsimileTelephoneNumber', X500ATTR_OID+'23': 'facsimileTelephoneNumber',
X500ATTR_OID + '20': 'telephoneNumber', X500ATTR_OID+'20': 'telephoneNumber',
X500ATTR_OID + '21': 'telexNumber', X500ATTR_OID+'21': 'telexNumber',
X500ATTR_OID + '26': 'registeredAddress', X500ATTR_OID+'26': 'registeredAddress',
X500ATTR_OID + '27': 'destinationIndicator', X500ATTR_OID+'27': 'destinationIndicator',
X500ATTR_OID + '24': 'x121Address', X500ATTR_OID+'24': 'x121Address',
X500ATTR_OID + '25': 'internationaliSDNNumber', X500ATTR_OID+'25': 'internationaliSDNNumber',
X500ATTR_OID + '28': 'preferredDeliveryMethod', X500ATTR_OID+'28': 'preferredDeliveryMethod',
X500ATTR_OID + '29': 'presentationAddress', X500ATTR_OID+'29': 'presentationAddress',
EDUPERSON_OID + '3': 'eduPersonOrgDN', EDUPERSON_OID+'3': 'eduPersonOrgDN',
NOREDUPERSON_OID + '3': 'norEduPersonBirthDate', NOREDUPERSON_OID+'3': 'norEduPersonBirthDate',
UMICH + '57': 'labeledURI', UMICH+'57': 'labeledURI',
UCL_DIR_PILOT + '1': 'uid', UCL_DIR_PILOT+'1': 'uid',
SCHAC + '1': 'schacMotherTongue', SCHAC+'1': 'schacMotherTongue',
SCHAC + '2': 'schacGender', SCHAC+'2': 'schacGender',
SCHAC + '3': 'schacDateOfBirth', SCHAC+'3': 'schacDateOfBirth',
SCHAC + '4': 'schacPlaceOfBirth', SCHAC+'4': 'schacPlaceOfBirth',
SCHAC + '5': 'schacCountryOfCitizenship', SCHAC+'5': 'schacCountryOfCitizenship',
SCHAC + '6': 'schacSn1', SCHAC+'6': 'schacSn1',
SCHAC + '7': 'schacSn2', SCHAC+'7': 'schacSn2',
SCHAC + '8': 'schacPersonalTitle', SCHAC+'8': 'schacPersonalTitle',
SCHAC + '9': 'schacHomeOrganization', SCHAC+'9': 'schacHomeOrganization',
SCHAC + '10': 'schacHomeOrganizationType', SCHAC+'10': 'schacHomeOrganizationType',
SCHAC + '11': 'schacCountryOfResidence', SCHAC+'11': 'schacCountryOfResidence',
SCHAC + '12': 'schacUserPresenceID', SCHAC+'12': 'schacUserPresenceID',
SCHAC + '13': 'schacPersonalPosition', SCHAC+'13': 'schacPersonalPosition',
SCHAC + '14': 'schacPersonalUniqueCode', SCHAC+'14': 'schacPersonalUniqueCode',
SCHAC + '15': 'schacPersonalUniqueID', SCHAC+'15': 'schacPersonalUniqueID',
SCHAC + '17': 'schacExpiryDate', SCHAC+'17': 'schacExpiryDate',
SCHAC + '18': 'schacUserPrivateAttribute', SCHAC+'18': 'schacUserPrivateAttribute',
SCHAC + '19': 'schacUserStatus', SCHAC+'19': 'schacUserStatus',
SCHAC + '20': 'schacProjectMembership', SCHAC+'20': 'schacProjectMembership',
SCHAC + '21': 'schacProjectSpecificRole', SCHAC+'21': 'schacProjectSpecificRole',
}, },
"to": { "to": {
'roleOccupant': X500ATTR_OID + '33', 'roleOccupant': X500ATTR_OID+'33',
'gn': X500ATTR_OID + '42', 'gn': X500ATTR_OID+'42',
'norEduPersonNIN': NOREDUPERSON_OID + '5', 'norEduPersonNIN': NOREDUPERSON_OID+'5',
'title': X500ATTR_OID + '12', 'title': X500ATTR_OID+'12',
'facsimileTelephoneNumber': X500ATTR_OID + '23', 'facsimileTelephoneNumber': X500ATTR_OID+'23',
'mail': UCL_DIR_PILOT + '3', 'mail': UCL_DIR_PILOT+'3',
'postOfficeBox': X500ATTR_OID + '18', 'postOfficeBox': X500ATTR_OID+'18',
'fax': X500ATTR_OID + '23', 'fax': X500ATTR_OID+'23',
'telephoneNumber': X500ATTR_OID + '20', 'telephoneNumber': X500ATTR_OID+'20',
'norEduPersonBirthDate': NOREDUPERSON_OID + '3', 'norEduPersonBirthDate': NOREDUPERSON_OID+'3',
'rfc822Mailbox': UCL_DIR_PILOT + '3', 'rfc822Mailbox': UCL_DIR_PILOT+'3',
'dc': UCL_DIR_PILOT + '25', 'dc': UCL_DIR_PILOT+'25',
'countryName': X500ATTR_OID + '6', 'countryName': X500ATTR_OID+'6',
'emailAddress': PKCS_9 + '1', 'emailAddress': PKCS_9+'1',
'employeeNumber': NETSCAPE_LDAP + '3', 'employeeNumber': NETSCAPE_LDAP+'3',
'organizationName': X500ATTR_OID + '10', 'organizationName': X500ATTR_OID+'10',
'eduPersonAssurance': EDUPERSON_OID + '11', 'eduPersonAssurance': EDUPERSON_OID+'11',
'norEduOrgAcronym': NOREDUPERSON_OID + '6', 'norEduOrgAcronym': NOREDUPERSON_OID+'6',
'registeredAddress': X500ATTR_OID + '26', 'registeredAddress': X500ATTR_OID+'26',
'physicalDeliveryOfficeName': X500ATTR_OID + '19', 'physicalDeliveryOfficeName': X500ATTR_OID+'19',
'associatedDomain': UCL_DIR_PILOT + '37', 'associatedDomain': UCL_DIR_PILOT+'37',
'l': X500ATTR_OID + '7', 'l': X500ATTR_OID+'7',
'stateOrProvinceName': X500ATTR_OID + '8', 'stateOrProvinceName': X500ATTR_OID+'8',
'federationFeideSchemaVersion': NOREDUPERSON_OID + '9', 'federationFeideSchemaVersion': NOREDUPERSON_OID+'9',
'pkcs9email': PKCS_9 + '1', 'pkcs9email': PKCS_9+'1',
'givenName': X500ATTR_OID + '42', 'givenName': X500ATTR_OID+'42',
'givenname': X500ATTR_OID + '42', 'givenname': X500ATTR_OID+'42',
'x500UniqueIdentifier': X500ATTR_OID + '45', 'x500UniqueIdentifier': X500ATTR_OID+'45',
'eduPersonNickname': EDUPERSON_OID + '2', 'eduPersonNickname': EDUPERSON_OID+'2',
'houseIdentifier': X500ATTR_OID + '51', 'houseIdentifier': X500ATTR_OID+'51',
'street': X500ATTR_OID + '9', 'street': X500ATTR_OID+'9',
'supportedAlgorithms': X500ATTR_OID + '52', 'supportedAlgorithms': X500ATTR_OID+'52',
'preferredLanguage': NETSCAPE_LDAP + '39', 'preferredLanguage': NETSCAPE_LDAP+'39',
'postalAddress': X500ATTR_OID + '16', 'postalAddress': X500ATTR_OID+'16',
'email': PKCS_9 + '1', 'email': PKCS_9+'1',
'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID + '8', 'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID+'8',
'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID + '8', 'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID+'8',
'c': X500ATTR_OID + '6', 'c': X500ATTR_OID+'6',
'teletexTerminalIdentifier': X500ATTR_OID + '22', 'teletexTerminalIdentifier': X500ATTR_OID+'22',
'o': X500ATTR_OID + '10', 'o': X500ATTR_OID+'10',
'cACertificate': X500ATTR_OID + '37', 'cACertificate': X500ATTR_OID+'37',
'telexNumber': X500ATTR_OID + '21', 'telexNumber': X500ATTR_OID+'21',
'ou': X500ATTR_OID + '11', 'ou': X500ATTR_OID+'11',
'initials': X500ATTR_OID + '43', 'initials': X500ATTR_OID+'43',
'eduPersonOrgUnitDN': EDUPERSON_OID + '4', 'eduPersonOrgUnitDN': EDUPERSON_OID+'4',
'deltaRevocationList': X500ATTR_OID + '53', 'deltaRevocationList': X500ATTR_OID+'53',
'norEduPersonLIN': NOREDUPERSON_OID + '4', 'norEduPersonLIN': NOREDUPERSON_OID+'4',
'supportedApplicationContext': X500ATTR_OID + '30', 'supportedApplicationContext': X500ATTR_OID+'30',
'eduPersonEntitlement': EDUPERSON_OID + '7', 'eduPersonEntitlement': EDUPERSON_OID+'7',
'generationQualifier': X500ATTR_OID + '44', 'generationQualifier': X500ATTR_OID+'44',
'eduPersonAffiliation': EDUPERSON_OID + '1', 'eduPersonAffiliation': EDUPERSON_OID+'1',
'edupersonaffiliation': EDUPERSON_OID + '1', 'edupersonaffiliation': EDUPERSON_OID+'1',
'eduPersonPrincipalName': EDUPERSON_OID + '6', 'eduPersonPrincipalName': EDUPERSON_OID+'6',
'edupersonprincipalname': EDUPERSON_OID + '6', 'edupersonprincipalname': EDUPERSON_OID+'6',
'localityName': X500ATTR_OID + '7', 'localityName': X500ATTR_OID+'7',
'owner': X500ATTR_OID + '32', 'owner': X500ATTR_OID+'32',
'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID + '2', 'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID+'2',
'searchGuide': X500ATTR_OID + '14', 'searchGuide': X500ATTR_OID+'14',
'certificateRevocationList': X500ATTR_OID + '39', 'certificateRevocationList': X500ATTR_OID+'39',
'organizationalUnitName': X500ATTR_OID + '11', 'organizationalUnitName': X500ATTR_OID+'11',
'userCertificate': X500ATTR_OID + '36', 'userCertificate': X500ATTR_OID+'36',
'preferredDeliveryMethod': X500ATTR_OID + '28', 'preferredDeliveryMethod': X500ATTR_OID+'28',
'internationaliSDNNumber': X500ATTR_OID + '25', 'internationaliSDNNumber': X500ATTR_OID+'25',
'uniqueMember': X500ATTR_OID + '50', 'uniqueMember': X500ATTR_OID+'50',
'departmentNumber': NETSCAPE_LDAP + '2', 'departmentNumber': NETSCAPE_LDAP+'2',
'enhancedSearchGuide': X500ATTR_OID + '47', 'enhancedSearchGuide': X500ATTR_OID+'47',
'userPKCS12': NETSCAPE_LDAP + '216', 'userPKCS12': NETSCAPE_LDAP+'216',
'eduPersonTargetedID': EDUPERSON_OID + '10', 'eduPersonTargetedID': EDUPERSON_OID+'10',
'norEduOrgUniqueNumber': NOREDUPERSON_OID + '1', 'norEduOrgUniqueNumber': NOREDUPERSON_OID+'1',
'x121Address': X500ATTR_OID + '24', 'x121Address': X500ATTR_OID+'24',
'destinationIndicator': X500ATTR_OID + '27', 'destinationIndicator': X500ATTR_OID+'27',
'eduPersonPrimaryAffiliation': EDUPERSON_OID + '5', 'eduPersonPrimaryAffiliation': EDUPERSON_OID+'5',
'surname': X500ATTR_OID + '4', 'surname': X500ATTR_OID+'4',
'jpegPhoto': UCL_DIR_PILOT + '60', 'jpegPhoto': UCL_DIR_PILOT+'60',
'eduPersonScopedAffiliation': EDUPERSON_OID + '9', 'eduPersonScopedAffiliation': EDUPERSON_OID+'9',
'edupersonscopedaffiliation': EDUPERSON_OID + '9', 'edupersonscopedaffiliation': EDUPERSON_OID+'9',
'protocolInformation': X500ATTR_OID + '48', 'protocolInformation': X500ATTR_OID+'48',
'knowledgeInformation': X500ATTR_OID + '2', 'knowledgeInformation': X500ATTR_OID+'2',
'employeeType': NETSCAPE_LDAP + '4', 'employeeType': NETSCAPE_LDAP+'4',
'userSMIMECertificate': NETSCAPE_LDAP + '40', 'userSMIMECertificate': NETSCAPE_LDAP+'40',
'member': X500ATTR_OID + '31', 'member': X500ATTR_OID+'31',
'streetAddress': X500ATTR_OID + '9', 'streetAddress': X500ATTR_OID+'9',
'dmdName': X500ATTR_OID + '54', 'dmdName': X500ATTR_OID+'54',
'postalCode': X500ATTR_OID + '17', 'postalCode': X500ATTR_OID+'17',
'pseudonym': X500ATTR_OID + '65', 'pseudonym': X500ATTR_OID+'65',
'dnQualifier': X500ATTR_OID + '46', 'dnQualifier': X500ATTR_OID+'46',
'crossCertificatePair': X500ATTR_OID + '40', 'crossCertificatePair': X500ATTR_OID+'40',
'eduPersonOrgDN': EDUPERSON_OID + '3', 'eduPersonOrgDN': EDUPERSON_OID+'3',
'authorityRevocationList': X500ATTR_OID + '38', 'authorityRevocationList': X500ATTR_OID+'38',
'displayName': NETSCAPE_LDAP + '241', 'displayName': NETSCAPE_LDAP+'241',
'businessCategory': X500ATTR_OID + '15', 'businessCategory': X500ATTR_OID+'15',
'serialNumber': X500ATTR_OID + '5', 'serialNumber': X500ATTR_OID+'5',
'norEduOrgUniqueIdentifier': NOREDUPERSON_OID + '7', 'norEduOrgUniqueIdentifier': NOREDUPERSON_OID+'7',
'st': X500ATTR_OID + '8', 'st': X500ATTR_OID+'8',
'carLicense': NETSCAPE_LDAP + '1', 'carLicense': NETSCAPE_LDAP+'1',
'presentationAddress': X500ATTR_OID + '29', 'presentationAddress': X500ATTR_OID+'29',
'sn': X500ATTR_OID + '4', 'sn': X500ATTR_OID+'4',
'domainComponent': UCL_DIR_PILOT + '25', 'domainComponent': UCL_DIR_PILOT+'25',
'labeledURI': UMICH + '57', 'labeledURI': UMICH+'57',
'uid': UCL_DIR_PILOT + '1', 'uid': UCL_DIR_PILOT+'1',
'schacMotherTongue': SCHAC + '1', 'schacMotherTongue':SCHAC+'1',
'schacGender': SCHAC + '2', 'schacGender': SCHAC+'2',
'schacDateOfBirth': SCHAC + '3', 'schacDateOfBirth':SCHAC+'3',
'schacPlaceOfBirth': SCHAC + '4', 'schacPlaceOfBirth': SCHAC+'4',
'schacCountryOfCitizenship': SCHAC + '5', 'schacCountryOfCitizenship':SCHAC+'5',
'schacSn1': SCHAC + '6', 'schacSn1': SCHAC+'6',
'schacSn2': SCHAC + '7', 'schacSn2': SCHAC+'7',
'schacPersonalTitle': SCHAC + '8', 'schacPersonalTitle':SCHAC+'8',
'schacHomeOrganization': SCHAC + '9', 'schacHomeOrganization': SCHAC+'9',
'schacHomeOrganizationType': SCHAC + '10', 'schacHomeOrganizationType': SCHAC+'10',
'schacCountryOfResidence': SCHAC + '11', 'schacCountryOfResidence': SCHAC+'11',
'schacUserPresenceID': SCHAC + '12', 'schacUserPresenceID': SCHAC+'12',
'schacPersonalPosition': SCHAC + '13', 'schacPersonalPosition': SCHAC+'13',
'schacPersonalUniqueCode': SCHAC + '14', 'schacPersonalUniqueCode': SCHAC+'14',
'schacPersonalUniqueID': SCHAC + '15', 'schacPersonalUniqueID': SCHAC+'15',
'schacExpiryDate': SCHAC + '17', 'schacExpiryDate': SCHAC+'17',
'schacUserPrivateAttribute': SCHAC + '18', 'schacUserPrivateAttribute': SCHAC+'18',
'schacUserStatus': SCHAC + '19', 'schacUserStatus': SCHAC+'19',
'schacProjectMembership': SCHAC + '20', 'schacProjectMembership': SCHAC+'20',
'schacProjectSpecificRole': SCHAC + '21', 'schacProjectSpecificRole': SCHAC+'21',
} }
} }

View File

@@ -9,182 +9,182 @@ UMICH = "urn:oid:1.3.6.1.4.1.250.1.57."
MAP = { MAP = {
"identifier": "urn:mace:shibboleth:1.0:attributeNamespace:uri", "identifier": "urn:mace:shibboleth:1.0:attributeNamespace:uri",
"fro": { "fro": {
EDUPERSON_OID + '2': 'eduPersonNickname', EDUPERSON_OID+'2': 'eduPersonNickname',
EDUPERSON_OID + '9': 'eduPersonScopedAffiliation', EDUPERSON_OID+'9': 'eduPersonScopedAffiliation',
EDUPERSON_OID + '11': 'eduPersonAssurance', EDUPERSON_OID+'11': 'eduPersonAssurance',
EDUPERSON_OID + '10': 'eduPersonTargetedID', EDUPERSON_OID+'10': 'eduPersonTargetedID',
EDUPERSON_OID + '4': 'eduPersonOrgUnitDN', EDUPERSON_OID+'4': 'eduPersonOrgUnitDN',
NOREDUPERSON_OID + '6': 'norEduOrgAcronym', NOREDUPERSON_OID+'6': 'norEduOrgAcronym',
NOREDUPERSON_OID + '7': 'norEduOrgUniqueIdentifier', NOREDUPERSON_OID+'7': 'norEduOrgUniqueIdentifier',
NOREDUPERSON_OID + '4': 'norEduPersonLIN', NOREDUPERSON_OID+'4': 'norEduPersonLIN',
EDUPERSON_OID + '1': 'eduPersonAffiliation', EDUPERSON_OID+'1': 'eduPersonAffiliation',
NOREDUPERSON_OID + '2': 'norEduOrgUnitUniqueNumber', NOREDUPERSON_OID+'2': 'norEduOrgUnitUniqueNumber',
NETSCAPE_LDAP + '40': 'userSMIMECertificate', NETSCAPE_LDAP+'40': 'userSMIMECertificate',
NOREDUPERSON_OID + '1': 'norEduOrgUniqueNumber', NOREDUPERSON_OID+'1': 'norEduOrgUniqueNumber',
NETSCAPE_LDAP + '241': 'displayName', NETSCAPE_LDAP+'241': 'displayName',
UCL_DIR_PILOT + '37': 'associatedDomain', UCL_DIR_PILOT+'37': 'associatedDomain',
EDUPERSON_OID + '6': 'eduPersonPrincipalName', EDUPERSON_OID+'6': 'eduPersonPrincipalName',
NOREDUPERSON_OID + '8': 'norEduOrgUnitUniqueIdentifier', NOREDUPERSON_OID+'8': 'norEduOrgUnitUniqueIdentifier',
NOREDUPERSON_OID + '9': 'federationFeideSchemaVersion', NOREDUPERSON_OID+'9': 'federationFeideSchemaVersion',
X500ATTR + '53': 'deltaRevocationList', X500ATTR+'53': 'deltaRevocationList',
X500ATTR + '52': 'supportedAlgorithms', X500ATTR+'52': 'supportedAlgorithms',
X500ATTR + '51': 'houseIdentifier', X500ATTR+'51': 'houseIdentifier',
X500ATTR + '50': 'uniqueMember', X500ATTR+'50': 'uniqueMember',
X500ATTR + '19': 'physicalDeliveryOfficeName', X500ATTR+'19': 'physicalDeliveryOfficeName',
X500ATTR + '18': 'postOfficeBox', X500ATTR+'18': 'postOfficeBox',
X500ATTR + '17': 'postalCode', X500ATTR+'17': 'postalCode',
X500ATTR + '16': 'postalAddress', X500ATTR+'16': 'postalAddress',
X500ATTR + '15': 'businessCategory', X500ATTR+'15': 'businessCategory',
X500ATTR + '14': 'searchGuide', X500ATTR+'14': 'searchGuide',
EDUPERSON_OID + '5': 'eduPersonPrimaryAffiliation', EDUPERSON_OID+'5': 'eduPersonPrimaryAffiliation',
X500ATTR + '12': 'title', X500ATTR+'12': 'title',
X500ATTR + '11': 'ou', X500ATTR+'11': 'ou',
X500ATTR + '10': 'o', X500ATTR+'10': 'o',
X500ATTR + '37': 'cACertificate', X500ATTR+'37': 'cACertificate',
X500ATTR + '36': 'userCertificate', X500ATTR+'36': 'userCertificate',
X500ATTR + '31': 'member', X500ATTR+'31': 'member',
X500ATTR + '30': 'supportedApplicationContext', X500ATTR+'30': 'supportedApplicationContext',
X500ATTR + '33': 'roleOccupant', X500ATTR+'33': 'roleOccupant',
X500ATTR + '32': 'owner', X500ATTR+'32': 'owner',
NETSCAPE_LDAP + '1': 'carLicense', NETSCAPE_LDAP+'1': 'carLicense',
PKCS_9 + '1': 'email', PKCS_9+'1': 'email',
NETSCAPE_LDAP + '3': 'employeeNumber', NETSCAPE_LDAP+'3': 'employeeNumber',
NETSCAPE_LDAP + '2': 'departmentNumber', NETSCAPE_LDAP+'2': 'departmentNumber',
X500ATTR + '39': 'certificateRevocationList', X500ATTR+'39': 'certificateRevocationList',
X500ATTR + '38': 'authorityRevocationList', X500ATTR+'38': 'authorityRevocationList',
NETSCAPE_LDAP + '216': 'userPKCS12', NETSCAPE_LDAP+'216': 'userPKCS12',
EDUPERSON_OID + '8': 'eduPersonPrimaryOrgUnitDN', EDUPERSON_OID+'8': 'eduPersonPrimaryOrgUnitDN',
X500ATTR + '9': 'street', X500ATTR+'9': 'street',
X500ATTR + '8': 'st', X500ATTR+'8': 'st',
NETSCAPE_LDAP + '39': 'preferredLanguage', NETSCAPE_LDAP+'39': 'preferredLanguage',
EDUPERSON_OID + '7': 'eduPersonEntitlement', EDUPERSON_OID+'7': 'eduPersonEntitlement',
X500ATTR + '2': 'knowledgeInformation', X500ATTR+'2': 'knowledgeInformation',
X500ATTR + '7': 'l', X500ATTR+'7': 'l',
X500ATTR + '6': 'c', X500ATTR+'6': 'c',
X500ATTR + '5': 'serialNumber', X500ATTR+'5': 'serialNumber',
X500ATTR + '4': 'sn', X500ATTR+'4': 'sn',
UCL_DIR_PILOT + '60': 'jpegPhoto', UCL_DIR_PILOT+'60': 'jpegPhoto',
X500ATTR + '65': 'pseudonym', X500ATTR+'65': 'pseudonym',
NOREDUPERSON_OID + '5': 'norEduPersonNIN', NOREDUPERSON_OID+'5': 'norEduPersonNIN',
UCL_DIR_PILOT + '3': 'mail', UCL_DIR_PILOT+'3': 'mail',
UCL_DIR_PILOT + '25': 'dc', UCL_DIR_PILOT+'25': 'dc',
X500ATTR + '40': 'crossCertificatePair', X500ATTR+'40': 'crossCertificatePair',
X500ATTR + '42': 'givenName', X500ATTR+'42': 'givenName',
X500ATTR + '43': 'initials', X500ATTR+'43': 'initials',
X500ATTR + '44': 'generationQualifier', X500ATTR+'44': 'generationQualifier',
X500ATTR + '45': 'x500UniqueIdentifier', X500ATTR+'45': 'x500UniqueIdentifier',
X500ATTR + '46': 'dnQualifier', X500ATTR+'46': 'dnQualifier',
X500ATTR + '47': 'enhancedSearchGuide', X500ATTR+'47': 'enhancedSearchGuide',
X500ATTR + '48': 'protocolInformation', X500ATTR+'48': 'protocolInformation',
X500ATTR + '54': 'dmdName', X500ATTR+'54': 'dmdName',
NETSCAPE_LDAP + '4': 'employeeType', NETSCAPE_LDAP+'4': 'employeeType',
X500ATTR + '22': 'teletexTerminalIdentifier', X500ATTR+'22': 'teletexTerminalIdentifier',
X500ATTR + '23': 'facsimileTelephoneNumber', X500ATTR+'23': 'facsimileTelephoneNumber',
X500ATTR + '20': 'telephoneNumber', X500ATTR+'20': 'telephoneNumber',
X500ATTR + '21': 'telexNumber', X500ATTR+'21': 'telexNumber',
X500ATTR + '26': 'registeredAddress', X500ATTR+'26': 'registeredAddress',
X500ATTR + '27': 'destinationIndicator', X500ATTR+'27': 'destinationIndicator',
X500ATTR + '24': 'x121Address', X500ATTR+'24': 'x121Address',
X500ATTR + '25': 'internationaliSDNNumber', X500ATTR+'25': 'internationaliSDNNumber',
X500ATTR + '28': 'preferredDeliveryMethod', X500ATTR+'28': 'preferredDeliveryMethod',
X500ATTR + '29': 'presentationAddress', X500ATTR+'29': 'presentationAddress',
EDUPERSON_OID + '3': 'eduPersonOrgDN', EDUPERSON_OID+'3': 'eduPersonOrgDN',
NOREDUPERSON_OID + '3': 'norEduPersonBirthDate', NOREDUPERSON_OID+'3': 'norEduPersonBirthDate',
}, },
"to": { "to":{
'roleOccupant': X500ATTR + '33', 'roleOccupant': X500ATTR+'33',
'gn': X500ATTR + '42', 'gn': X500ATTR+'42',
'norEduPersonNIN': NOREDUPERSON_OID + '5', 'norEduPersonNIN': NOREDUPERSON_OID+'5',
'title': X500ATTR + '12', 'title': X500ATTR+'12',
'facsimileTelephoneNumber': X500ATTR + '23', 'facsimileTelephoneNumber': X500ATTR+'23',
'mail': UCL_DIR_PILOT + '3', 'mail': UCL_DIR_PILOT+'3',
'postOfficeBox': X500ATTR + '18', 'postOfficeBox': X500ATTR+'18',
'fax': X500ATTR + '23', 'fax': X500ATTR+'23',
'telephoneNumber': X500ATTR + '20', 'telephoneNumber': X500ATTR+'20',
'norEduPersonBirthDate': NOREDUPERSON_OID + '3', 'norEduPersonBirthDate': NOREDUPERSON_OID+'3',
'rfc822Mailbox': UCL_DIR_PILOT + '3', 'rfc822Mailbox': UCL_DIR_PILOT+'3',
'dc': UCL_DIR_PILOT + '25', 'dc': UCL_DIR_PILOT+'25',
'countryName': X500ATTR + '6', 'countryName': X500ATTR+'6',
'emailAddress': PKCS_9 + '1', 'emailAddress': PKCS_9+'1',
'employeeNumber': NETSCAPE_LDAP + '3', 'employeeNumber': NETSCAPE_LDAP+'3',
'organizationName': X500ATTR + '10', 'organizationName': X500ATTR+'10',
'eduPersonAssurance': EDUPERSON_OID + '11', 'eduPersonAssurance': EDUPERSON_OID+'11',
'norEduOrgAcronym': NOREDUPERSON_OID + '6', 'norEduOrgAcronym': NOREDUPERSON_OID+'6',
'registeredAddress': X500ATTR + '26', 'registeredAddress': X500ATTR+'26',
'physicalDeliveryOfficeName': X500ATTR + '19', 'physicalDeliveryOfficeName': X500ATTR+'19',
'associatedDomain': UCL_DIR_PILOT + '37', 'associatedDomain': UCL_DIR_PILOT+'37',
'l': X500ATTR + '7', 'l': X500ATTR+'7',
'stateOrProvinceName': X500ATTR + '8', 'stateOrProvinceName': X500ATTR+'8',
'federationFeideSchemaVersion': NOREDUPERSON_OID + '9', 'federationFeideSchemaVersion': NOREDUPERSON_OID+'9',
'pkcs9email': PKCS_9 + '1', 'pkcs9email': PKCS_9+'1',
'givenName': X500ATTR + '42', 'givenName': X500ATTR+'42',
'x500UniqueIdentifier': X500ATTR + '45', 'x500UniqueIdentifier': X500ATTR+'45',
'eduPersonNickname': EDUPERSON_OID + '2', 'eduPersonNickname': EDUPERSON_OID+'2',
'houseIdentifier': X500ATTR + '51', 'houseIdentifier': X500ATTR+'51',
'street': X500ATTR + '9', 'street': X500ATTR+'9',
'supportedAlgorithms': X500ATTR + '52', 'supportedAlgorithms': X500ATTR+'52',
'preferredLanguage': NETSCAPE_LDAP + '39', 'preferredLanguage': NETSCAPE_LDAP+'39',
'postalAddress': X500ATTR + '16', 'postalAddress': X500ATTR+'16',
'email': PKCS_9 + '1', 'email': PKCS_9+'1',
'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID + '8', 'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID+'8',
'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID + '8', 'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID+'8',
'c': X500ATTR + '6', 'c': X500ATTR+'6',
'teletexTerminalIdentifier': X500ATTR + '22', 'teletexTerminalIdentifier': X500ATTR+'22',
'o': X500ATTR + '10', 'o': X500ATTR+'10',
'cACertificate': X500ATTR + '37', 'cACertificate': X500ATTR+'37',
'telexNumber': X500ATTR + '21', 'telexNumber': X500ATTR+'21',
'ou': X500ATTR + '11', 'ou': X500ATTR+'11',
'initials': X500ATTR + '43', 'initials': X500ATTR+'43',
'eduPersonOrgUnitDN': EDUPERSON_OID + '4', 'eduPersonOrgUnitDN': EDUPERSON_OID+'4',
'deltaRevocationList': X500ATTR + '53', 'deltaRevocationList': X500ATTR+'53',
'norEduPersonLIN': NOREDUPERSON_OID + '4', 'norEduPersonLIN': NOREDUPERSON_OID+'4',
'supportedApplicationContext': X500ATTR + '30', 'supportedApplicationContext': X500ATTR+'30',
'eduPersonEntitlement': EDUPERSON_OID + '7', 'eduPersonEntitlement': EDUPERSON_OID+'7',
'generationQualifier': X500ATTR + '44', 'generationQualifier': X500ATTR+'44',
'eduPersonAffiliation': EDUPERSON_OID + '1', 'eduPersonAffiliation': EDUPERSON_OID+'1',
'eduPersonPrincipalName': EDUPERSON_OID + '6', 'eduPersonPrincipalName': EDUPERSON_OID+'6',
'localityName': X500ATTR + '7', 'localityName': X500ATTR+'7',
'owner': X500ATTR + '32', 'owner': X500ATTR+'32',
'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID + '2', 'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID+'2',
'searchGuide': X500ATTR + '14', 'searchGuide': X500ATTR+'14',
'certificateRevocationList': X500ATTR + '39', 'certificateRevocationList': X500ATTR+'39',
'organizationalUnitName': X500ATTR + '11', 'organizationalUnitName': X500ATTR+'11',
'userCertificate': X500ATTR + '36', 'userCertificate': X500ATTR+'36',
'preferredDeliveryMethod': X500ATTR + '28', 'preferredDeliveryMethod': X500ATTR+'28',
'internationaliSDNNumber': X500ATTR + '25', 'internationaliSDNNumber': X500ATTR+'25',
'uniqueMember': X500ATTR + '50', 'uniqueMember': X500ATTR+'50',
'departmentNumber': NETSCAPE_LDAP + '2', 'departmentNumber': NETSCAPE_LDAP+'2',
'enhancedSearchGuide': X500ATTR + '47', 'enhancedSearchGuide': X500ATTR+'47',
'userPKCS12': NETSCAPE_LDAP + '216', 'userPKCS12': NETSCAPE_LDAP+'216',
'eduPersonTargetedID': EDUPERSON_OID + '10', 'eduPersonTargetedID': EDUPERSON_OID+'10',
'norEduOrgUniqueNumber': NOREDUPERSON_OID + '1', 'norEduOrgUniqueNumber': NOREDUPERSON_OID+'1',
'x121Address': X500ATTR + '24', 'x121Address': X500ATTR+'24',
'destinationIndicator': X500ATTR + '27', 'destinationIndicator': X500ATTR+'27',
'eduPersonPrimaryAffiliation': EDUPERSON_OID + '5', 'eduPersonPrimaryAffiliation': EDUPERSON_OID+'5',
'surname': X500ATTR + '4', 'surname': X500ATTR+'4',
'jpegPhoto': UCL_DIR_PILOT + '60', 'jpegPhoto': UCL_DIR_PILOT+'60',
'eduPersonScopedAffiliation': EDUPERSON_OID + '9', 'eduPersonScopedAffiliation': EDUPERSON_OID+'9',
'protocolInformation': X500ATTR + '48', 'protocolInformation': X500ATTR+'48',
'knowledgeInformation': X500ATTR + '2', 'knowledgeInformation': X500ATTR+'2',
'employeeType': NETSCAPE_LDAP + '4', 'employeeType': NETSCAPE_LDAP+'4',
'userSMIMECertificate': NETSCAPE_LDAP + '40', 'userSMIMECertificate': NETSCAPE_LDAP+'40',
'member': X500ATTR + '31', 'member': X500ATTR+'31',
'streetAddress': X500ATTR + '9', 'streetAddress': X500ATTR+'9',
'dmdName': X500ATTR + '54', 'dmdName': X500ATTR+'54',
'postalCode': X500ATTR + '17', 'postalCode': X500ATTR+'17',
'pseudonym': X500ATTR + '65', 'pseudonym': X500ATTR+'65',
'dnQualifier': X500ATTR + '46', 'dnQualifier': X500ATTR+'46',
'crossCertificatePair': X500ATTR + '40', 'crossCertificatePair': X500ATTR+'40',
'eduPersonOrgDN': EDUPERSON_OID + '3', 'eduPersonOrgDN': EDUPERSON_OID+'3',
'authorityRevocationList': X500ATTR + '38', 'authorityRevocationList': X500ATTR+'38',
'displayName': NETSCAPE_LDAP + '241', 'displayName': NETSCAPE_LDAP+'241',
'businessCategory': X500ATTR + '15', 'businessCategory': X500ATTR+'15',
'serialNumber': X500ATTR + '5', 'serialNumber': X500ATTR+'5',
'norEduOrgUniqueIdentifier': NOREDUPERSON_OID + '7', 'norEduOrgUniqueIdentifier': NOREDUPERSON_OID+'7',
'st': X500ATTR + '8', 'st': X500ATTR+'8',
'carLicense': NETSCAPE_LDAP + '1', 'carLicense': NETSCAPE_LDAP+'1',
'presentationAddress': X500ATTR + '29', 'presentationAddress': X500ATTR+'29',
'sn': X500ATTR + '4', 'sn': X500ATTR+'4',
'domainComponent': UCL_DIR_PILOT + '25', 'domainComponent': UCL_DIR_PILOT+'25',
} }
} }

View File

@@ -14,12 +14,12 @@ BASE = "http://lingon.ladok.umu.se:8087"
#BASE = "http://localhost:8087" #BASE = "http://localhost:8087"
CONFIG = { CONFIG = {
"entityid": "%s/sp.xml" % BASE, "entityid" : "%s/sp.xml" % BASE,
"name": "SAML2 test tool", "name" : "SAML2 test tool",
"description": "Simplest possible", "description": "Simplest possible",
"service": { "service": {
"sp": { "sp": {
"endpoints": { "endpoints":{
"assertion_consumer_service": [ "assertion_consumer_service": [
("%s/acs/post" % BASE, BINDING_HTTP_POST), ("%s/acs/post" % BASE, BINDING_HTTP_POST),
("%s/acs/redirect" % BASE, BINDING_HTTP_REDIRECT), ("%s/acs/redirect" % BASE, BINDING_HTTP_REDIRECT),
@@ -30,27 +30,27 @@ CONFIG = {
"single_logout_service": [ "single_logout_service": [
("%s/sls" % BASE, BINDING_SOAP) ("%s/sls" % BASE, BINDING_SOAP)
], ],
"artifact_resolution_service": [ "artifact_resolution_service":[
("%s/ars" % BASE, BINDING_SOAP) ("%s/ars" % BASE, BINDING_SOAP)
], ],
"manage_name_id_service": [ "manage_name_id_service":[
("%s/mni" % BASE, BINDING_HTTP_POST), ("%s/mni" % BASE, BINDING_HTTP_POST),
("%s/mni" % BASE, BINDING_HTTP_REDIRECT), ("%s/mni" % BASE, BINDING_HTTP_REDIRECT),
("%s/mni" % BASE, BINDING_SOAP), ("%s/mni" % BASE, BINDING_SOAP),
("%s/acs/artifact" % BASE, BINDING_HTTP_ARTIFACT) ("%s/acs/artifact" % BASE, BINDING_HTTP_ARTIFACT)
], ],
"discovery_response": [ "discovery_response":[
("%s/disco" % BASE, BINDING_DISCO) ("%s/disco" % BASE, BINDING_DISCO)
] ]
} }
} }
}, },
"key_file": "keys/mykey.pem", "key_file" : "keys/mykey.pem",
"cert_file": "keys/mycert.pem", "cert_file" : "keys/mycert.pem",
"xmlsec_binary": XMLSEC_BINARY, "xmlsec_binary" : XMLSEC_BINARY,
"subject_data": "subject_data.db", "subject_data": "subject_data.db",
"accepted_time_diff": 60, "accepted_time_diff": 60,
"attribute_map_dir": "attributemaps", "attribute_map_dir" : "attributemaps",
"organization": { "organization": {
"name": ("AB Exempel", "se"), "name": ("AB Exempel", "se"),
"display_name": ("AB Exempel", "se"), "display_name": ("AB Exempel", "se"),
@@ -68,3 +68,4 @@ CONFIG = {
"secret": "0123456789", "secret": "0123456789",
"only_use_keys_in_metadata": False "only_use_keys_in_metadata": False
} }

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
from saml2.saml import NAME_FORMAT_URI from saml2.saml import NAME_FORMAT_URI
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rolandh' __author__ = 'rolandh'
@@ -75,4 +74,4 @@ info = {
"name_format": NAME_FORMAT_URI "name_format": NAME_FORMAT_URI
} }
print json.dumps(info, **JSON_DUMPS_ARGS) print json.dumps(info)

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
from saml2.saml import NAME_FORMAT_URI from saml2.saml import NAME_FORMAT_URI
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rolandh' __author__ = 'rolandh'
@@ -65,4 +64,4 @@ info = {
"name_format": NAME_FORMAT_URI "name_format": NAME_FORMAT_URI
} }
print json.dumps(info, **JSON_DUMPS_ARGS) print json.dumps(info)

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
from saml2.saml import AUTHN_PASSWORD from saml2.saml import AUTHN_PASSWORD
from saml2test import JSON_DUMPS_ARGS
__author__ = 'rolandh' __author__ = 'rolandh'
@@ -41,4 +40,4 @@ info = {
"userid": "roland" "userid": "roland"
} }
print json.dumps(info, **JSON_DUMPS_ARGS) print json.dumps(info)