Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Hans Hörberg 2015-05-26 09:44:56 +02:00
commit 5a1add6827
30 changed files with 136 additions and 58 deletions

View File

@ -42,6 +42,7 @@ tests_require = [
'python-memcached >= 1.51',
'pytest',
'mako',
'webob',
#'pytest-coverage',
]

View File

@ -6,6 +6,7 @@ import pprint
import types
import argparse
import sys
import six
import logging
import imp
@ -356,7 +357,7 @@ class SAML2client(object):
item = {"id": key, "name": val["name"]}
try:
_desc = val["descr"]
if isinstance(_desc, basestring):
if isinstance(_desc, six.string_types):
item["descr"] = _desc
else:
item["descr"] = "\n".join(_desc)
@ -377,7 +378,7 @@ class SAML2client(object):
item = {"id": key, "name": val["name"]}
try:
_desc = val["descr"]
if isinstance(_desc, basestring):
if isinstance(_desc, six.string_types):
item["descr"] = _desc
else:
item["descr"] = "\n".join(_desc)

View File

@ -2,6 +2,7 @@ __author__ = 'rohe0002'
import json
import logging
import six
from urlparse import urlparse
from bs4 import BeautifulSoup
@ -34,7 +35,8 @@ def pick_interaction(interactions, _base="", content="", req=None):
_match += 1
else:
_c = _bs.title.contents
if isinstance(_c, list) and not isinstance(_c, basestring):
if isinstance(_c, list) and not isinstance(
_c, six.string_types):
for _line in _c:
if val in _line:
_match += 1
@ -165,7 +167,7 @@ def pick_form(response, url=None, **kwargs):
_default = _ava["value"]
try:
orig_val = form[prop]
if isinstance(orig_val, basestring):
if isinstance(orig_val, six.string_types):
if orig_val == _default:
_form = form
elif _default in orig_val:

View File

@ -30,7 +30,7 @@ class AuthnRequest_UnknownExtension(AuthnRequest):
return message
OPERATIONS = {
'authn_unkown-issuer': {
'authn_unknown-issuer': {
"name": 'AuthnRequest with unknown issuer',
"descr": 'AuthnRequest with unknown issuer',
"sequence": [AuthnRequest_UnknownIssuer],
@ -38,7 +38,7 @@ OPERATIONS = {
"tests": {"pre": [CheckSaml2IntMetaData],
"post": [CheckSaml2IntAttributes]}
},
'authn_unkown-extension': {
'authn_unknown-extension': {
"name": 'AuthnRequest with unknown extension',
"descr": 'AuthnRequest with unknown extension',
"sequence": [AuthnRequest_UnknownExtension],
@ -46,4 +46,4 @@ OPERATIONS = {
"tests": {"pre": [CheckSaml2IntMetaData],
"post": [CheckSaml2IntAttributes]}
},
}
}

View File

@ -675,7 +675,11 @@ class SamlBase(ExtensionContainer):
return ElementTree.tostring(self._to_element_tree(), encoding="UTF-8")
def __str__(self):
return self.to_string()
# Yes this is confusing. http://bugs.python.org/issue10942
x = self.to_string()
if not isinstance(x, six.string_types):
x = x.decode('utf-8')
return x
def keyswv(self):
""" Return the keys of attributes or children that has values

View File

@ -6,7 +6,7 @@ import logging
import re
from saml2.saml import NAME_FORMAT_URI
import six
import xmlenc
from saml2 import xmlenc
from saml2 import saml

View File

@ -4,6 +4,7 @@ import base64
import datetime
import dateutil.parser
import pytz
import six
from OpenSSL import crypto
from os.path import join
from os import remove
@ -154,10 +155,13 @@ class OpenSSLWrapper(object):
tmp_cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
tmp_key = None
if cipher_passphrase is not None:
passphrase = cipher_passphrase["passphrase"]
if isinstance(cipher_passphrase["passphrase"],
six.string_types):
passphrase = passphrase.encode('utf-8')
tmp_key = crypto.dump_privatekey(crypto.FILETYPE_PEM, k,
cipher_passphrase["cipher"],
cipher_passphrase[
"passphrase"])
passphrase)
else:
tmp_key = crypto.dump_privatekey(crypto.FILETYPE_PEM, k)
if write_to_file:
@ -190,7 +194,7 @@ class OpenSSLWrapper(object):
f.close()
def read_str_from_file(self, file, type="pem"):
f = open(file)
f = open(file, 'rt')
str_data = f.read()
f.close()
@ -257,7 +261,10 @@ class OpenSSLWrapper(object):
cert.set_pubkey(req_cert.get_pubkey())
cert.sign(ca_key, hash_alg)
return crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
cert_dump = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
if isinstance(cert_dump, six.string_types):
return cert_dump
return cert_dump.decode('utf-8')
def verify_chain(self, cert_chain_str_list, cert_str):
"""
@ -327,6 +334,8 @@ class OpenSSLWrapper(object):
"signed certificate.")
cert_algorithm = cert.get_signature_algorithm()
if six.PY3:
cert_algorithm = cert_algorithm.decode('ascii')
cert_asn1 = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)
@ -342,7 +351,9 @@ class OpenSSLWrapper(object):
signature_payload = cert_signature_decoded.payload
if signature_payload[0] != '\x00':
sig_pay0 = signature_payload[0]
if ((isinstance(sig_pay0, int) and sig_pay0 != 0) or
(isinstance(sig_pay0, str) and sig_pay0 != '\x00')):
return (False,
"The certificate should not contain any unused bits.")
@ -355,4 +366,4 @@ class OpenSSLWrapper(object):
except crypto.Error as e:
return False, "Certificate is incorrectly signed."
except Exception as e:
return False, "Certificate is not valid for an unknown reason."
return False, "Certificate is not valid for an unknown reason. %s" % str(e)

View File

@ -6,8 +6,8 @@
to conclude its tasks.
"""
import threading
from urllib import urlencode
from urlparse import urlparse
from six.moves.urllib.parse import urlencode
from six.moves.urllib.parse import urlparse
import six
from saml2.entity import Entity
@ -25,7 +25,7 @@ import saml2
import time
from saml2.soap import make_soap_enveloped_saml_thingy
from urlparse import parse_qs
from six.moves.urllib.parse import parse_qs
from saml2.s_utils import signature, UnravelError, exception_trace
from saml2.s_utils import do_attributes

View File

@ -8,6 +8,7 @@ import os
import re
import logging
import logging.handlers
import six
from importlib import import_module
@ -300,7 +301,7 @@ class Config(object):
def unicode_convert(self, item):
try:
return unicode(item, "utf-8")
return six.text_type(item, "utf-8")
except TypeError:
_uc = self.unicode_convert
if isinstance(item, dict):

View File

@ -5,6 +5,7 @@ import logging
from hashlib import sha1
from Crypto.PublicKey import RSA
import requests
import six
from saml2.metadata import ENDPOINTS
from saml2.profile import paos, ecp
from saml2.soap import parse_soap_enveloped_saml_artifact_resolve
@ -157,7 +158,7 @@ class Entity(HTTPBase):
self.sec = security_context(self.config)
if virtual_organization:
if isinstance(virtual_organization, basestring):
if isinstance(virtual_organization, six.string_types):
self.vorg = self.config.vorg[virtual_organization]
elif isinstance(virtual_organization, VirtualOrg):
self.vorg = virtual_organization
@ -282,7 +283,7 @@ class Entity(HTTPBase):
#logger.error("Bindings: %s" % bindings)
#logger.error("Entities: %s" % self.metadata)
raise SAMLError("Unkown entity or unsupported bindings")
raise SAMLError("Unknown entity or unsupported bindings")
def message_args(self, message_id=0):
if not message_id:

View File

@ -8,6 +8,7 @@ import hashlib
import shelve
import logging
import six
logger = logging.getLogger(__name__)
@ -21,13 +22,23 @@ class Eptid(object):
md5 = hashlib.md5()
for arg in args:
md5.update(arg.encode("utf-8"))
md5.update(sp)
md5.update(self.secret)
if isinstance(sp, six.binary_type):
md5.update(sp)
else:
md5.update(sp.encode('utf-8'))
if isinstance(self.secret, six.binary_type):
md5.update(self.secret)
else:
md5.update(self.secret.encode('utf-8'))
md5.digest()
hashval = md5.hexdigest()
if isinstance(hashval, six.binary_type):
hashval = hashval.decode('ascii')
return "!".join([idp, sp, hashval])
def __getitem__(self, key):
if six.PY3 and isinstance(key, six.binary_type):
key = key.decode('utf-8')
return self._db[key]
def __setitem__(self, key, value):
@ -47,4 +58,7 @@ class Eptid(object):
class EptidShelve(Eptid):
def __init__(self, secret, filename):
Eptid.__init__(self, secret)
self._db = shelve.open(filename, writeback=True)
if six.PY3:
if filename.endswith('.db'):
filename = filename.rsplit('.db', 1)[0]
self._db = shelve.open(filename, writeback=True, protocol=2)

View File

@ -1,4 +1,5 @@
import calendar
import six
from six.moves import http_cookiejar
import copy
import re
@ -260,7 +261,7 @@ class HTTPBase(object):
:param typ: Whether a Request, Response or Artifact
:return: dictionary
"""
if not isinstance(message, basestring):
if not isinstance(message, six.string_types):
message = "%s" % (message,)
return http_form_post_message(message, destination, relay_state, typ)
@ -375,7 +376,7 @@ class HTTPBase(object):
:param key: Key to use for signing
:return: dictionary
"""
if not isinstance(message, basestring):
if not isinstance(message, six.string_types):
message = "%s" % (message,)
return http_redirect_message(message, destination, relay_state, typ,

View File

@ -1,12 +1,13 @@
import copy
import shelve
import logging
import six
from hashlib import sha256
from urllib import quote
from urllib import unquote
from six.moves.urllib.parse import quote
from six.moves.urllib.parse import unquote
from saml2 import SAMLError
from saml2.s_utils import rndstr
from saml2.s_utils import rndbytes
from saml2.s_utils import PolicyError
from saml2.saml import NameID
from saml2.saml import NAMEID_FORMAT_PERSISTENT
@ -45,6 +46,16 @@ def code(item):
return ",".join(_res)
def code_binary(item):
"""
Return a binary 'code' suitable for hashing.
"""
code_str = code(item)
if isinstance(code_str, six.string_types):
return code_str.encode('utf-8')
return code_str
def decode(txt):
"""Turns a coded string by code() into a NameID class instance.
@ -66,7 +77,7 @@ class IdentDB(object):
Keeps a list of all nameIDs returned per SP
"""
def __init__(self, db, domain="", name_qualifier=""):
if isinstance(db, basestring):
if isinstance(db, six.string_types):
self.db = shelve.open(db)
else:
self.db = db
@ -74,11 +85,17 @@ class IdentDB(object):
self.name_qualifier = name_qualifier
def _create_id(self, nformat, name_qualifier="", sp_name_qualifier=""):
_id = sha256(rndstr(32))
_id = sha256(rndbytes(32))
if not isinstance(nformat, six.binary_type):
nformat = nformat.encode('utf-8')
_id.update(nformat)
if name_qualifier:
if not isinstance(name_qualifier, six.binary_type):
name_qualifier = name_qualifier.encode('utf-8')
_id.update(name_qualifier)
if sp_name_qualifier:
if not isinstance(sp_name_qualifier, six.binary_type):
sp_name_qualifier = sp_name_qualifier.encode('utf-8')
_id.update(sp_name_qualifier)
return _id.hexdigest()
@ -94,7 +111,7 @@ class IdentDB(object):
:param ident: user identifier
:param name_id: NameID instance
"""
if isinstance(ident, unicode):
if isinstance(ident, six.string_types):
ident = ident.encode("utf-8")
# One user may have more than one NameID defined

View File

@ -3,6 +3,7 @@ import logging
import os
import sys
import json
import six
from hashlib import sha1
from os.path import isfile, join
@ -487,6 +488,8 @@ class InMemoryMetaData(MetaData):
try:
for srv in ent[desc]:
if "artifact_resolution_service" in srv:
if isinstance(eid, six.string_types):
eid = eid.encode('utf-8')
s = sha1(eid)
res[s.digest()] = ent
except KeyError:
@ -541,7 +544,7 @@ class MetaDataFile(InMemoryMetaData):
"""
def __init__(self, onts, attrc, filename=None, cert=None, **kwargs):
super(MetaDataFile, self).__init__(onts, attrc, **kwargs)
if not file:
if not filename:
raise SAMLError('No file specified.')
self.filename = filename
self.cert = cert

View File

@ -9,7 +9,7 @@ from saml2.eptid import Eptid
from saml2.mdstore import InMemoryMetaData
from saml2.s_utils import PolicyError
from saml2.ident import code, IdentDB, Unknown
from saml2.ident import code_binary, IdentDB, Unknown
from saml2.mdie import to_dict, from_dict
from saml2 import md
@ -59,7 +59,7 @@ class SessionStorageMDB(object):
def store_assertion(self, assertion, to_sign):
name_id = assertion.subject.name_id
nkey = sha1(code(name_id)).hexdigest()
nkey = sha1(code_binary(name_id)).hexdigest()
doc = {
"name_id_key": nkey,
@ -94,7 +94,7 @@ class SessionStorageMDB(object):
:return:
"""
result = []
key = sha1(code(name_id)).hexdigest()
key = sha1(code_binary(name_id)).hexdigest()
for item in self.assertion.find({"name_id_key": key}):
assertion = from_dict(item["assertion"], ONTS, True)
if session_index or requested_context:
@ -114,7 +114,7 @@ class SessionStorageMDB(object):
def remove_authn_statements(self, name_id):
logger.debug("remove authn about: %s" % name_id)
key = sha1(code(name_id)).hexdigest()
key = sha1(code_binary(name_id)).hexdigest()
for item in self.assertion.find({"name_id_key": key}):
self.assertion.remove(item["_id"])

View File

@ -20,6 +20,7 @@ import logging
from saml2.sigver import REQ_ORDER
from saml2.sigver import RESP_ORDER
from saml2.sigver import SIGNER_ALGS
import six
logger = logging.getLogger(__name__)
@ -57,7 +58,7 @@ def http_form_post_message(message, location, relay_state="",
"""
response = ["<head>", """<title>SAML 2.0 POST</title>""", "</head><body>"]
if not isinstance(message, basestring):
if not isinstance(message, six.string_types):
message = "%s" % (message,)
if typ == "SAMLRequest" or typ == "SAMLResponse":
@ -94,7 +95,7 @@ def http_redirect_message(message, location, relay_state="", typ="SAMLRequest",
:return: A tuple containing header information and a HTML message.
"""
if not isinstance(message, basestring):
if not isinstance(message, six.string_types):
message = "%s" % (message,)
_order = None
@ -163,7 +164,7 @@ def make_soap_enveloped_saml_thingy(thingy, header_parts=None):
body.tag = '{%s}Body' % NAMESPACE
envelope.append(body)
if isinstance(thingy, basestring):
if isinstance(thingy, six.string_types):
# remove the first XML version/encoding line
logger.debug("thingy0: %s" % thingy)
_part = thingy.split("\n")
@ -174,6 +175,8 @@ def make_soap_enveloped_saml_thingy(thingy, header_parts=None):
_child.tag = '{%s}FuddleMuddle' % DUMMY_NAMESPACE
body.append(_child)
_str = ElementTree.tostring(envelope, encoding="UTF-8")
if isinstance(_str, six.binary_type):
_str = _str.decode('utf-8')
logger.debug("SOAP precursor: %s" % _str)
# find an remove the namespace definition
i = _str.find(DUMMY_NAMESPACE)
@ -247,7 +250,7 @@ def packager(identifier):
try:
return PACKING[identifier]
except KeyError:
raise Exception("Unkown binding type: %s" % identifier)
raise Exception("Unknown binding type: %s" % identifier)
def factory(binding, message, location, relay_state="", typ="SAMLRequest"):

View File

@ -1,6 +1,6 @@
import logging
from attribute_converter import to_local
from saml2.attribute_converter import to_local
from saml2 import time_util, BINDING_HTTP_REDIRECT
from saml2.s_utils import OtherError

View File

@ -4,6 +4,7 @@
import calendar
import logging
import six
from saml2.samlp import STATUS_VERSION_MISMATCH
from saml2.samlp import STATUS_AUTHN_FAILED
from saml2.samlp import STATUS_INVALID_ATTR_NAME_OR_VALUE
@ -1001,6 +1002,8 @@ class AuthnResponse(StatusResponse):
"not_on_or_after": nooa, "authn_info": self.authn_info()}
def __str__(self):
if not isinstance(self.xmlstr, six.string_types):
return "%s" % self.xmlstr.decode("utf-8")
return "%s" % self.xmlstr
def verify_attesting_entity(self, address):

View File

@ -12,6 +12,7 @@ import platform
import shelve
import traceback
import saml2
import six
from urlparse import parse_qs, urlparse
from saml2.md import Extensions
from saml2 import xmldsig as ds
@ -555,7 +556,7 @@ class SAML2Plugin(object):
def add_metadata(self, environ, identity):
""" Add information to the knowledge I have about the user """
name_id = identity['repoze.who.userid']
if isinstance(name_id, basestring):
if isinstance(name_id, six.string_types):
try:
# Make sure that userids authenticated by another plugin
# don't cause problems here.

View File

@ -164,8 +164,17 @@ def rndstr(size=16, alphabet=""):
"""
rng = random.SystemRandom()
if not alphabet:
alphabet = string.letters[0:52] + string.digits
return str().join(rng.choice(alphabet) for _ in range(size))
alphabet = string.ascii_letters[0:52] + string.digits
return type(alphabet)().join(rng.choice(alphabet) for _ in range(size))
def rndbytes(size=16, alphabet=""):
"""
Returns rndstr always as a binary type
"""
x = rndstr(size, alphabet)
if isinstance(x, six.string_types):
return x.encode('utf-8')
return x
def sid():

View File

@ -15,6 +15,7 @@ import urllib
from time import mktime
from binascii import hexlify
import six
from Crypto.PublicKey.RSA import importKey
from Crypto.Signature import PKCS1_v1_5
@ -729,7 +730,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
def __init__(self, xmlsec_binary, **kwargs):
CryptoBackend.__init__(self, **kwargs)
assert (isinstance(xmlsec_binary, basestring))
assert (isinstance(xmlsec_binary, six.string_types))
self.xmlsec = xmlsec_binary
if os.environ.get('PYSAML2_KEEP_XMLSEC_TMP', None):
self._xmlsec_delete_tmpfiles = False
@ -1395,7 +1396,7 @@ class SecurityContext(object):
_certs = []
certs = []
for cert in _certs:
if isinstance(cert, basestring):
if isinstance(cert, six.string_types):
certs.append(make_temp(pem_format(cert), suffix=".pem",
decode=False,
delete=self._xmlsec_delete_tmpfiles))

View File

@ -305,7 +305,7 @@ def validate_value_type(value, spec):
{'base': 'string'}
"""
if "maxlen" in spec:
return len(value) <= spec["maxlen"]
return len(value) <= int(spec["maxlen"])
if spec["base"] == "string":
if "enumeration" in spec:

View File

@ -1,5 +1,6 @@
import inspect
import json
import six
__author__ = 'rolandh'
@ -91,7 +92,7 @@ class ResponseInfo(Information):
self._status = self.status
_msg = conv.last_content
if isinstance(_msg, basestring):
if isinstance(_msg, six.string_types):
self._message = _msg
else:
self._message = _msg.to_dict()

View File

@ -2,6 +2,7 @@ __author__ = 'rohe0002'
import json
import logging
import six
from urlparse import urlparse
from bs4 import BeautifulSoup
@ -125,8 +126,8 @@ class Interaction(object):
_match += 1
else:
_c = _bs.title.contents
if isinstance(_c, list) and not isinstance(_c,
basestring):
if isinstance(_c, list) and not isinstance(
_c, six.string_types):
for _line in _c:
if val in _line:
_match += 1
@ -186,7 +187,7 @@ class Interaction(object):
_default = _ava["value"]
try:
orig_val = form[prop]
if isinstance(orig_val, basestring):
if isinstance(orig_val, six.string_types):
if orig_val == _default:
_form = form
elif _default in orig_val:

View File

@ -1,5 +1,6 @@
import logging
import json
import six
from urlparse import urlparse
@ -163,7 +164,7 @@ def pick_form(response, content, url=None, **kwargs):
_default = _ava["value"]
try:
orig_val = form[prop]
if isinstance(orig_val, basestring):
if isinstance(orig_val, six.string_types):
if orig_val == _default:
_form = form
elif _default in orig_val:

View File

@ -3,6 +3,7 @@ import sys
import traceback
import logging
from urlparse import parse_qs
import six
from saml2test.opfunc import Operation
from saml2test import CheckError, FatalError
@ -64,7 +65,7 @@ class Conversation(object):
raise CheckError
def do_check(self, test, **kwargs):
if isinstance(test, basestring):
if isinstance(test, six.string_types):
chk = self.check_factory(test)(**kwargs)
else:
chk = test(**kwargs)

View File

@ -5,6 +5,7 @@ import os
import traceback
import urllib
import sys
import six
from urlparse import parse_qs
from saml2 import BINDING_HTTP_REDIRECT, class_name
@ -93,7 +94,7 @@ class Conversation():
raise CheckError
def do_check(self, test, **kwargs):
if isinstance(test, basestring):
if isinstance(test, six.string_types):
chk = self.check_factory(test)(**kwargs)
else:
chk = test(**kwargs)

View File

@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
import datetime
import re
from urllib import quote_plus
from six.moves.urllib.parse import quote_plus
from saml2.httpbase import HTTPBase
from saml2.mdstore import MetadataStore, MetaDataMDX

View File

@ -170,6 +170,6 @@ class TestPopulationMemoryBased():
"eduPersonEntitlement": "Anka"}
info = self.population.get_info_from(nid, IDP_OTHER)
assert info.keys() == ["not_on_or_after", "name_id", "ava"]
assert list(info.keys()) == ["not_on_or_after", "name_id", "ava"]
assert info["name_id"] == nid
assert info["ava"] == {"eduPersonEntitlement": "Anka"}

View File

@ -174,7 +174,7 @@ class TestGenerateCertificates(unittest.TestCase):
request=True)
cert_str = osw.create_cert_signed_certificate(ca_cert_str, ca_key_str,
req_cert_str,
passphrase="qwerty")
passphrase=b"qwerty")
valid = False
try: