Added logger specification to the configuration
This commit is contained in:
@@ -104,6 +104,8 @@ class Saml2Client(object):
|
||||
self.metadata = self.config.metadata
|
||||
self.sec = security_context(config)
|
||||
|
||||
self.logger = self.config.setup_logger()
|
||||
|
||||
if virtual_organization:
|
||||
self.vorg = VirtualOrg(self, virtual_organization)
|
||||
else:
|
||||
@@ -180,6 +182,9 @@ class Saml2Client(object):
|
||||
except KeyError:
|
||||
raise Exception("Missing entity_id specification")
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
reply_addr = self._service_url()
|
||||
|
||||
resp = None
|
||||
@@ -255,7 +260,10 @@ class Saml2Client(object):
|
||||
|
||||
request.name_id_policy = name_id_policy
|
||||
request.issuer = self.issuer(spentityid)
|
||||
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if log:
|
||||
log.info("REQUEST: %s" % request)
|
||||
|
||||
@@ -315,7 +323,10 @@ class Saml2Client(object):
|
||||
location = self._sso_location(entityid)
|
||||
service_url = self._service_url()
|
||||
my_name = self._my_name()
|
||||
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if log:
|
||||
log.info("spentityid: %s" % spentityid)
|
||||
log.info("location: %s" % location)
|
||||
@@ -419,7 +430,10 @@ class Saml2Client(object):
|
||||
:param log: Function to use for logging
|
||||
:return: The attributes returned
|
||||
"""
|
||||
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
session_id = sid()
|
||||
issuer = self.issuer(issuer_id)
|
||||
|
||||
@@ -448,7 +462,7 @@ class Saml2Client(object):
|
||||
log.info("Verifying response")
|
||||
|
||||
try:
|
||||
aresp = attribute_response(self.config, "", issuer, log=log)
|
||||
aresp = attribute_response(self.config, issuer, log)
|
||||
except Exception, exc:
|
||||
if log:
|
||||
log.error("%s", (exc,))
|
||||
@@ -468,8 +482,7 @@ class Saml2Client(object):
|
||||
return None
|
||||
|
||||
def construct_logout_request(self, subject_id, destination,
|
||||
issuer_entity_id,
|
||||
reason=None, expire=None):
|
||||
issuer_entity_id, reason=None, expire=None):
|
||||
""" Constructs a LogoutRequest
|
||||
|
||||
:param subject_id: The identifier of the subject
|
||||
@@ -526,7 +539,10 @@ class Saml2Client(object):
|
||||
if SOAP binding has been used the just the result of that
|
||||
conversation.
|
||||
"""
|
||||
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if log:
|
||||
log.info("logout request for: %s" % subject_id)
|
||||
|
||||
@@ -548,7 +564,9 @@ class Saml2Client(object):
|
||||
# for all where I can use the SOAP binding, do those first
|
||||
not_done = entity_ids[:]
|
||||
response = False
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
for entity_id in entity_ids:
|
||||
response = False
|
||||
|
||||
@@ -645,6 +663,9 @@ class Saml2Client(object):
|
||||
:return: 4-tuple of (session_id of the last sent logout request,
|
||||
response message, response headers and message)
|
||||
"""
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if log:
|
||||
log.info("state: %s" % (self.state,))
|
||||
status = self.state[response.in_response_to]
|
||||
@@ -679,6 +700,8 @@ class Saml2Client(object):
|
||||
"""
|
||||
|
||||
response = None
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if xmlstr:
|
||||
try:
|
||||
@@ -732,6 +755,8 @@ class Saml2Client(object):
|
||||
"""
|
||||
headers = []
|
||||
success = False
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
try:
|
||||
saml_request = get['SAMLRequest']
|
||||
@@ -779,7 +804,9 @@ class Saml2Client(object):
|
||||
:param subject_id: the id of the current logged user
|
||||
:return: What is returned also depends on which binding is used.
|
||||
"""
|
||||
|
||||
if log is None:
|
||||
log = self.logger
|
||||
|
||||
if binding == BINDING_HTTP_REDIRECT:
|
||||
return self.http_redirect_logout_request(request, subject_id, log)
|
||||
|
||||
|
||||
@@ -3,9 +3,15 @@
|
||||
__author__ = 'rolandh'
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
from saml2 import BINDING_SOAP, BINDING_HTTP_REDIRECT
|
||||
from saml2 import metadata
|
||||
from saml2 import root_logger
|
||||
|
||||
from saml2.attribute_converter import ac_factory
|
||||
from saml2.assertion import Policy
|
||||
|
||||
@@ -16,6 +22,7 @@ COMMON_ARGS = ["entityid", "xmlsec_binary", "debug", "key_file", "cert_file",
|
||||
"contact_person",
|
||||
"name_form",
|
||||
"virtual_organization",
|
||||
"logger"
|
||||
]
|
||||
|
||||
SP_ARGS = [
|
||||
@@ -48,6 +55,24 @@ SPEC = {
|
||||
"aa": COMMON_ARGS + COMPLEX_ARGS + AA_IDP_ARGS,
|
||||
}
|
||||
|
||||
# --------------- Logging stuff ---------------
|
||||
|
||||
LOG_LEVEL = {'debug': logging.DEBUG,
|
||||
'info': logging.INFO,
|
||||
'warning': logging.WARNING,
|
||||
'error': logging.ERROR,
|
||||
'critical': logging.CRITICAL}
|
||||
|
||||
LOG_HANDLER = {
|
||||
"rotating": logging.handlers.RotatingFileHandler,
|
||||
"syslog": logging.handlers.SysLogHandler,
|
||||
"timerotate": logging.handlers.TimedRotatingFileHandler,
|
||||
}
|
||||
|
||||
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
class Config(object):
|
||||
def_context = ""
|
||||
|
||||
@@ -193,6 +218,52 @@ class Config(object):
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def setup_logger(self):
|
||||
try:
|
||||
_logconf = self.logger
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
if root_logger.level != logging.NOTSET: # Someone got there before me
|
||||
return root_logger
|
||||
|
||||
if "loglevel" in _logconf:
|
||||
root_logger.setLevel(LOG_LEVEL[_logconf["loglevel"]])
|
||||
else: # reasonable default
|
||||
root_logger.setLevel(logging.WARNING)
|
||||
|
||||
handler = None
|
||||
for htyp in LOG_HANDLER:
|
||||
if htyp in _logconf:
|
||||
if htyp == "syslog":
|
||||
args = _logconf[htyp]
|
||||
if "socktype" in args:
|
||||
import socket
|
||||
if args["socktype"] == "dgram":
|
||||
args["socktype"] = socket.SOCK_DGRAM
|
||||
elif args["socktype"] == "stream":
|
||||
args["socktype"] = socket.SOCK_STREAM
|
||||
else:
|
||||
raise Exception("Unknown socktype!")
|
||||
handler = LOG_HANDLER[htyp](**args)
|
||||
else:
|
||||
handler = LOG_HANDLER[htyp](**_logconf[htyp])
|
||||
break
|
||||
|
||||
if handler is None:
|
||||
raise Exception("You have to define a log handler")
|
||||
|
||||
if "format" in _logconf:
|
||||
formatter = logging.Formatter(_logconf["format"])
|
||||
else:
|
||||
formatter = logging.Formatter(LOG_FORMAT)
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
root_logger.addHandler(handler)
|
||||
|
||||
return root_logger
|
||||
|
||||
|
||||
class SPConfig(Config):
|
||||
def_context = "sp"
|
||||
|
||||
@@ -238,7 +309,7 @@ class SPConfig(Config):
|
||||
|
||||
return []
|
||||
|
||||
def idps(self, langpref=["en"]):
|
||||
def idps(self, langpref=None):
|
||||
""" Returns a dictionary of usefull IdPs, the keys being the
|
||||
entity ID of the service and the names of the services as values
|
||||
|
||||
@@ -246,6 +317,9 @@ class SPConfig(Config):
|
||||
is used.
|
||||
:return: Dictionary
|
||||
"""
|
||||
if langpref is None:
|
||||
langpref = ["en"]
|
||||
|
||||
if self.idp:
|
||||
return dict([(e, nd[0]) for (e,
|
||||
nd) in self.metadata.idps(langpref).items() if e in self.idp])
|
||||
|
||||
@@ -214,9 +214,13 @@ class Server(object):
|
||||
self.conf = config
|
||||
else:
|
||||
raise Exception("Missing configuration")
|
||||
|
||||
|
||||
if self.log is None:
|
||||
self.log = self.conf.setup_logger()
|
||||
|
||||
self.metadata = self.conf.metadata
|
||||
self.sec = security_context(self.conf, log)
|
||||
|
||||
# if cache:
|
||||
# if isinstance(cache, basestring):
|
||||
# self.cache = Cache(cache)
|
||||
@@ -638,7 +642,7 @@ class Server(object):
|
||||
sp_entity_id = request.issuer.text.strip()
|
||||
|
||||
binding = None
|
||||
destination = ""
|
||||
destinations = []
|
||||
for binding in bindings:
|
||||
destinations = self.conf.single_logout_services(sp_entity_id,
|
||||
binding)
|
||||
|
||||
@@ -40,5 +40,13 @@ CONFIG={
|
||||
"email_address": ["tech@eample.com", "tech@example.org"],
|
||||
"contact_type": "technical"
|
||||
},
|
||||
]
|
||||
],
|
||||
"logger": {
|
||||
"rotating": {
|
||||
"filename": "sp.log",
|
||||
"maxBytes": 100000,
|
||||
"backupCount": 5,
|
||||
},
|
||||
"loglevel": "warning",
|
||||
}
|
||||
}
|
||||
54
tests/server_conf_syslog.py
Normal file
54
tests/server_conf_syslog.py
Normal file
@@ -0,0 +1,54 @@
|
||||
__author__ = 'rolandh'
|
||||
|
||||
CONFIG={
|
||||
"entityid" : "urn:mace:example.com:saml:roland:sp",
|
||||
"name" : "urn:mace:example.com:saml:roland:sp",
|
||||
"description": "My own SP",
|
||||
"service": {
|
||||
"sp": {
|
||||
"endpoints":{
|
||||
"assertion_consumer_service": ["http://lingon.catalogix.se:8087/"],
|
||||
},
|
||||
"required_attributes": ["surName", "givenName", "mail"],
|
||||
"optional_attributes": ["title"],
|
||||
"idp": ["urn:mace:example.com:saml:roland:idp"],
|
||||
}
|
||||
},
|
||||
"debug" : 1,
|
||||
"key_file" : "test.key",
|
||||
"cert_file" : "test.pem",
|
||||
"xmlsec_binary" : "/usr/local/bin/xmlsec1",
|
||||
"metadata": {
|
||||
"local": ["idp.xml", "vo_metadata.xml"],
|
||||
},
|
||||
"virtual_organization" : {
|
||||
"urn:mace:example.com:it:tek":{
|
||||
"nameid_format" : "urn:oid:1.3.6.1.4.1.1466.115.121.1.15-NameID",
|
||||
"common_identifier": "umuselin",
|
||||
}
|
||||
},
|
||||
"subject_data": "subject_data.db",
|
||||
"accepted_time_diff": 60,
|
||||
"attribute_map_dir" : "attributemaps",
|
||||
"organization": {
|
||||
"name": ("AB Exempel", "se"),
|
||||
"display_name": ("AB Exempel", "se"),
|
||||
"url": "http://www.example.org",
|
||||
},
|
||||
"contact_person": [{
|
||||
"given_name": "Roland",
|
||||
"sur_name": "Hedberg",
|
||||
"telephone_number": "+46 70 100 0000",
|
||||
"email_address": ["tech@eample.com", "tech@example.org"],
|
||||
"contact_type": "technical"
|
||||
},
|
||||
],
|
||||
"logger": {
|
||||
"syslog": {
|
||||
"address": ("localhost", 514),
|
||||
"facility": "local3",
|
||||
"socktype": "dgram",
|
||||
},
|
||||
"loglevel": "info",
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,9 @@ from saml2.config import SPConfig, IdPConfig, Config
|
||||
from saml2.metadata import MetaData
|
||||
from py.test import raises
|
||||
|
||||
from saml2 import root_logger
|
||||
import logging
|
||||
|
||||
sp1 = {
|
||||
"entityid" : "urn:mace:umu.se:saml:roland:sp",
|
||||
"service": {
|
||||
@@ -196,6 +199,40 @@ def test_wayf():
|
||||
idps = c.idps(["se","en"])
|
||||
assert idps == {'urn:mace:example.com:saml:roland:idp': 'Exempel AB'}
|
||||
|
||||
c.setup_logger()
|
||||
|
||||
assert root_logger.level != logging.NOTSET
|
||||
assert root_logger.level == logging.WARNING
|
||||
assert len(root_logger.handlers) == 1
|
||||
assert isinstance(root_logger.handlers[0],
|
||||
logging.handlers.RotatingFileHandler)
|
||||
handler = root_logger.handlers[0]
|
||||
assert handler.backupCount == 5
|
||||
assert handler.maxBytes == 100000
|
||||
assert handler.mode == "a"
|
||||
assert root_logger.name == "pySAML2"
|
||||
assert root_logger.level == 30
|
||||
|
||||
def test_conf_syslog():
|
||||
c = SPConfig().load_file("server_conf_syslog")
|
||||
c.context = "sp"
|
||||
|
||||
# otherwise the logger setting is not changed
|
||||
root_logger.level == logging.NOTSET
|
||||
c.setup_logger()
|
||||
|
||||
assert root_logger.level != logging.NOTSET
|
||||
assert root_logger.level == logging.INFO
|
||||
assert len(root_logger.handlers) == 1
|
||||
assert isinstance(root_logger.handlers[0],
|
||||
logging.handlers.SyslogHandler)
|
||||
handler = root_logger.handlers[0]
|
||||
assert handler.backupCount == 5
|
||||
assert handler.maxBytes == 100000
|
||||
assert handler.mode == "a"
|
||||
assert root_logger.name == "pySAML2"
|
||||
assert root_logger.level == 20
|
||||
|
||||
#noinspection PyUnresolvedReferences
|
||||
def test_3():
|
||||
cnf = Config()
|
||||
|
||||
Reference in New Issue
Block a user