def choose_session_storage(self):
        _spec = self.config.getattr("session_storage", "idp")
        if not _spec:
            return SessionStorage()
        elif isinstance(_spec, basestring):
            if _spec.lower() == "memory":
                return SessionStorage()
        else:  # Should be tuple
            typ, data = _spec
            if typ.lower() == "mongodb":
                return SessionStorageMDB(data)

        raise NotImplementedError("No such storage type implemented")
Exemple #2
0
    def choose_session_storage(self):
        _spec = self.config.getattr("session_storage", "idp")
        if not _spec:
            return SessionStorage()
        elif isinstance(_spec, six.string_types):
            if _spec.lower() == "memory":
                return SessionStorage()
        else:  # Should be tuple
            typ, data = _spec
            if typ.lower() == "mongodb":
                from saml2.mongo_store import SessionStorageMDB
                return SessionStorageMDB(database=data, collection="session")

        raise NotImplementedError("No such storage type implemented")
Exemple #3
0
 def __init__(self, config_file="", config=None, _cache="", stype="idp"):
     Entity.__init__(self, stype, config, config_file)
     self.init_config(stype)
     self._cache = _cache
     self.ticket = {}
     self.authn = {}
     self.assertion = {}
     self.user2uid = {}
     self.uid2user = {}
     self.session_db = SessionStorage()
Exemple #4
0
class Server(Entity):
    """ A class that does things that IdPs or AAs do """
    def __init__(self, config_file="", config=None, _cache="", stype="idp"):
        Entity.__init__(self, stype, config, config_file)
        self.init_config(stype)
        self._cache = _cache
        self.ticket = {}
        self.authn = {}
        self.assertion = {}
        self.user2uid = {}
        self.uid2user = {}
        self.session_db = SessionStorage()

    def init_config(self, stype="idp"):
        """ Remaining init of the server configuration 
        
        :param stype: The type of Server ("idp"/"aa")
        """
        if stype == "aa":
            return
        
        try:
            # subject information is stored in a database
            # default database is a shelve database which is OK in some setups
            dbspec = self.config.getattr("subject_data", "idp")
            idb = None
            if not dbspec:
                pass
            elif isinstance(dbspec, basestring):
                idb = shelve.open(dbspec, writeback=True)
            else:  # database spec is a a 2-tuple (type, address)
                print >> sys.stderr, "DBSPEC: %s" % (dbspec,)
                (typ, addr) = dbspec
                if typ == "shelve":
                    idb = shelve.open(addr, writeback=True)
                elif typ == "memcached":
                    idb = memcache.Client(addr)
                elif typ == "dict":  # in-memory dictionary
                    idb = {}
                elif typ == "mongodb":
                    from mongodict import MongoDict
                    idb = MongoDict(host='localhost', port=27017,
                                    database=addr, collection='store')

            if idb is not None:
                self.ident = IdentDB(idb)
            else:
                raise Exception("Couldn't open identity database: %s" %
                                (dbspec,))
        except AttributeError:
            self.ident = None

    def close_shelve_db(self):
        """Close the shelve db to prevent file system locking issues"""
        if self.ident:
            self.ident.db.close()

    def wants(self, sp_entity_id, index=None):
        """ Returns what attributes the SP requires and which are optional
        if any such demands are registered in the Metadata.

        :param sp_entity_id: The entity id of the SP
        :param index: which of the attribute consumer services its all about
        :return: 2-tuple, list of required and list of optional attributes
        """
        return self.metadata.attribute_requirement(sp_entity_id, index)

    # -------------------------------------------------------------------------

    def parse_authn_request(self, enc_request, binding=BINDING_HTTP_REDIRECT):
        """Parse a Authentication Request
        
        :param enc_request: The request in its transport format
        :param binding: Which binding that was used to transport the message
            to this entity.
        :return: A dictionary with keys:
            consumer_url - as gotten from the SPs entity_id and the metadata
            id - the id of the request
            sp_entity_id - the entity id of the SP
            request - The verified request
        """

        return self._parse_request(enc_request, AuthnRequest,
                                   "single_sign_on_service", binding)

    def parse_attribute_query(self, xml_string, binding):
        """ Parse an attribute query
        
        :param xml_string: The Attribute Query as an XML string
        :param binding: Which binding that was used for the request
        :return: A query instance
        """

        return self._parse_request(xml_string, AttributeQuery,
                                   "attribute_service", binding)

    def parse_authz_decision_query(self, xml_string, binding):
        """ Parse an attribute query

        :param xml_string: The Authz decision Query as an XML string
        :return: Query instance
        """

        return self._parse_request(xml_string, AuthzDecisionQuery,
                                   "authz_service", binding)

    def parse_assertion_id_request(self, xml_string, binding):
        """ Parse an assertion id query

        :param xml_string: The AssertionIDRequest as an XML string
        :return: Query instance
        """

        return self._parse_request(xml_string, AssertionIDRequest,
                                   "assertion_id_request_service", binding)

    def parse_authn_query(self, xml_string, binding):
        """ Parse an authn query

        :param xml_string: The AuthnQuery as an XML string
        :return: Query instance
        """

        return self._parse_request(xml_string, AuthnQuery,
                                   "authn_query_service", binding)

    def parse_name_id_mapping_request(self, xml_string, binding):
        """ Parse a nameid mapping request

        :param xml_string: The NameIDMappingRequest as an XML string
        :return: Query instance
        """

        return self._parse_request(xml_string, NameIDMappingRequest,
                                   "name_id_mapping_service", binding)

    # ------------------------------------------------------------------------

    # ------------------------------------------------------------------------

    def _authn_response(self, in_response_to, consumer_url,
                        sp_entity_id, identity=None, name_id=None,
                        status=None, authn=None,
                        authn_decl=None, issuer=None, policy=None,
                        sign_assertion=False, sign_response=False):
        """ Create a response. A layer of indirection.
        
        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param sp_entity_id: The entity identifier of the SP
        :param identity: A dictionary with attributes and values that are
            expected to be the bases for the assertion in the response.
        :param name_id: The identifier of the subject
        :param status: The status of the response
        :param authn: A 2-tuple denoting the authn class and the authn
            authority.
        :param authn_decl:
        :param issuer: The issuer of the response
        :param sign_assertion: Whether the assertion should be signed or not
        :param sign_response: Whether the response should be signed or not
        :return: A response instance
        """

        to_sign = []
        args = {}
        if identity:
            _issuer = self._issuer(issuer)
            ast = Assertion(identity)
            if policy is None:
                policy = Policy()
            try:
                ast.apply_policy(sp_entity_id, policy, self.metadata)
            except MissingValue, exc:
                return self.create_error_response(in_response_to, consumer_url,
                                                  exc, sign_response)

            if authn:  # expected to be a 2-tuple class+authority
                (authn_class, authn_authn) = authn
                assertion = ast.construct(sp_entity_id, in_response_to,
                                          consumer_url, name_id,
                                          self.config.attribute_converters,
                                          policy, issuer=_issuer,
                                          authn_class=authn_class,
                                          authn_auth=authn_authn)
                self.session_db.store_authn_statement(assertion.authn_statement,
                                                      name_id)
            elif authn_decl:
                assertion = ast.construct(sp_entity_id, in_response_to,
                                          consumer_url, name_id,
                                          self.config.attribute_converters,
                                          policy, issuer=_issuer,
                                          authn_decl=authn_decl)
                self.session_db.store_authn_statement(assertion.authn_statement,
                                                      name_id)
            else:
                assertion = ast.construct(sp_entity_id, in_response_to,
                                          consumer_url, name_id,
                                          self.config.attribute_converters,
                                          policy, issuer=_issuer)

            if sign_assertion:
                assertion.signature = pre_signature_part(assertion.id,
                                                         self.sec.my_cert, 1)
                # Just the assertion or the response and the assertion ?
                to_sign = [(class_name(assertion), assertion.id)]

            # Store which assertion that has been sent to which SP about which
            # subject.

            # self.cache.set(assertion.subject.name_id.text,
            #                 sp_entity_id, {"ava": identity, "authn": authn},
            #                 assertion.conditions.not_on_or_after)

            args["assertion"] = assertion

            self.session_db.store_assertion(assertion, to_sign)

        return self._response(in_response_to, consumer_url, status, issuer,
                              sign_response, to_sign, **args)