Merge pull request #27 from dv10den/master
Added documentation structure
This commit is contained in:
BIN
doc/_static/ViewmeonGitHub.png
vendored
Normal file
BIN
doc/_static/ViewmeonGitHub.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
23
doc/conf.py
23
doc/conf.py
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
5
doc/make.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
rm -f saml2test*
|
||||||
|
sphinx-apidoc -F -o ../doc/ ../src/saml2test
|
||||||
|
make clean
|
||||||
|
make html
|
||||||
@@ -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()
|
||||||
7
setup.py
7
setup.py
@@ -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",
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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"]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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():
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
# Group of test suites
|
|
||||||
@@ -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)],
|
||||||
@@ -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',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
Reference in New Issue
Block a user