Пример #1
0
    def fetch_server_assignment(self, private_id, public_id):
        if self.peer is None:
            raise HSSStillConnecting()
        if not self.peer.alive:
            raise HSSConnectionLost()
        # Constants to match the enumerated values in 3GPP TS 29.229 s6.3.15
        REGISTRATION = 1
        UNREGISTERED_USER = 3

        _log.debug("Sending Server-Assignment request for %s/%s" % (private_id, public_id))
        req = self.cx.getCommandRequest(self.peer.stack, "Server-Assignment", True)
        self.session_id += 1
        req.addAVP(self.cx.getAVP('Session-Id').withOctetString("%s;%u;%u" % (settings.PUBLIC_HOSTNAME, self.session_id >> 32, self.session_id & 0xffffffff)))
        req.addAVP(self.cx.getAVP('Auth-Session-State').withInteger32(1))
        req.addAVP(self.cx.getAVP('Destination-Realm').withOctetString(self.peer.realm))
        req.addAVP(self.cx.getAVP('Destination-Host').withOctetString(self.peer.identity))

        if private_id:
            # withOctetString takes a sequence of bytes, not a Unicode
            # string, so call bytes() on private_id and public_id
            req.addAVP(self.cx.getAVP('User-Name').withOctetString(bytes(private_id)))

        req.addAVP(self.cx.getAVP('Public-Identity').withOctetString(bytes(public_id)))
        req.addAVP(self.cx.getAVP('Server-Name').withOctetString(self.server_name))
        if private_id:
            req.addAVP(self.cx.getAVP('Server-Assignment-Type').withInteger32(REGISTRATION))
        else:
            req.addAVP(self.cx.getAVP('Server-Assignment-Type').withInteger32(UNREGISTERED_USER))
        req.addAVP(self.cx.getAVP('User-Data-Already-Available').withInteger32(0))

        # Send off message to HSS
        self.peer.stack.sendByPeer(self.peer, req)

        # Hook up our deferred to the callback
        d = defer.Deferred()
        self.app.add_pending_response(req, d)
        answer = yield d

        _log.debug("Received Server-Assignment response for %s:" % private_id)
        user_data = self.cx.findFirstAVP(answer, "User-Data")

        if not user_data:
            self.log_diameter_error(answer)

            # If the error is an Overload response, increment the HSS penalty
            # counter
            if self.get_diameter_result_code(answer) == 3004:
                penaltycounter.incr_hss_penalty_count()
                raise HSSOverloaded()
            else:
                # Translated into a 404 higher up the stack
                defer.returnValue(None)

        defer.returnValue(user_data.getOctetString())
Пример #2
0
    def fetch_location_info(self, public_id, originating, auth_type):
        if self.peer is None:
            raise HSSStillConnecting()
        if not self.peer.alive:
            raise HSSConnectionLost()

        _log.debug("Sending Location-Info request for %s" % (public_id))
        req = self.cx.getCommandRequest(self.peer.stack, "Location-Info", True)
        self.session_id += 1
        req.addAVP(self.cx.getAVP('Session-Id').withOctetString("%s;%u;%u" % (settings.PUBLIC_HOSTNAME, self.session_id >> 32, self.session_id & 0xffffffff)))
        req.addAVP(self.cx.getAVP('Auth-Session-State').withInteger32(1))
        req.addAVP(self.cx.getAVP('Destination-Realm').withOctetString(self.peer.realm))
        req.addAVP(self.cx.getAVP('Destination-Host').withOctetString(self.peer.identity))

        # withOctetString takes a sequence of bytes, not a Unicode string, so call
        # bytes() on public_id
        req.addAVP(self.cx.getAVP('Public-Identity').withOctetString(bytes(public_id)))
        if auth_type is not None:
            req.addAVP(self.cx.getAVP('User-Authorization-Type').withInteger32(AUTH_TYPES["CAPAB"]))
        if originating is not None:
            req.addAVP(self.cx.getAVP('Originating-Request').withInteger32(ORIGINATING))

        # Send off message to HSS
        self.peer.stack.sendByPeer(self.peer, req)

        # Hook up our deferred to the callback
        d = defer.Deferred()
        self.app.add_pending_response(req, d)
        answer = yield d

        _log.debug("Received Location-Info response for %s:" % public_id)

        result_code = self.get_diameter_result_code(answer)
        exp_result_code = self.get_diameter_exp_result_code(answer)

        if result_code == resultcodes.DIAMETER_SUCCESS or exp_result_code == resultcodes.DIAMETER_UNREGISTERED_SERVICE:
            location_information = {}
            server_name = self.cx.findFirstAVP(answer, "Server-Name")
            if result_code == resultcodes.DIAMETER_SUCCESS and server_name:
                location_information[JSON_RC] = result_code
                location_information[JSON_SCSCF] = server_name.getOctetString()
            else:
                location_information[JSON_RC] = result_code if result_code == resultcodes.DIAMETER_SUCCESS else exp_result_code
                server_capabilities = self.cx.findFirstAVP(answer, "Server-Capabilities")
                man_capabilities = []
                opt_capabilities = []
                if server_capabilities:
                    man_capabilities = [avp.getInteger32() for avp in self.cx.findAVP(server_capabilities, "Mandatory-Capability")]
                    opt_capabilities = [avp.getInteger32() for avp in self.cx.findAVP(server_capabilities, "Optional-Capability")]
                location_information[JSON_MAN_CAP] = man_capabilities
                location_information[JSON_OPT_CAP] = opt_capabilities
        elif exp_result_code in [resultcodes.DIAMETER_ERROR_USER_UNKNOWN, resultcodes.DIAMETER_ERROR_IDENTITY_NOT_REGISTERED]:
            self.log_diameter_error(answer)
            raise UserNotIdentifiable()
        elif result_code == resultcodes.DIAMETER_TOO_BUSY:
            # If the error is an Overload response, increment the HSS penalty counter
            penaltycounter.incr_hss_penalty_count()
            self.log_diameter_error(answer)
            raise HSSOverloaded()
        else:
            # Translated into a 500 higher up the stack
            defer.returnValue(None)

        defer.returnValue(location_information)
Пример #3
0
    def fetch_user_auth(self, private_id, public_id, visited_network, auth_type):
        if self.peer is None:
            raise HSSStillConnecting()
        if not self.peer.alive:
            raise HSSConnectionLost()

        _log.debug("Sending User-Authorization request for %s/%s" % (private_id, public_id))
        req = self.cx.getCommandRequest(self.peer.stack, "User-Authorization", True)
        self.session_id += 1
        req.addAVP(self.cx.getAVP('Session-Id').withOctetString("%s;%u;%u" % (settings.PUBLIC_HOSTNAME, self.session_id >> 32, self.session_id & 0xffffffff)))
        req.addAVP(self.cx.getAVP('Auth-Session-State').withInteger32(1))
        req.addAVP(self.cx.getAVP('Destination-Realm').withOctetString(self.peer.realm))
        req.addAVP(self.cx.getAVP('Destination-Host').withOctetString(self.peer.identity))

        # withOctetString takes a sequence of bytes, not a Unicode string, so call
        # bytes() on private_id, public_id and visited_network
        req.addAVP(self.cx.getAVP('Public-Identity').withOctetString(bytes(public_id)))
        req.addAVP(self.cx.getAVP('Visited-Network-Identifier').withOctetString(bytes(visited_network)))
        req.addAVP(self.cx.getAVP('User-Authorization-Type').withInteger32(auth_type))
        req.addAVP(self.cx.getAVP('User-Name').withOctetString(bytes(private_id)))

        # Send off message to HSS
        self.peer.stack.sendByPeer(self.peer, req)

        # Hook up our deferred to the callback
        d = defer.Deferred()
        self.app.add_pending_response(req, d)
        answer = yield d

        _log.debug("Received User-Authorization response for %s/%s:" % (private_id, public_id))
        result_code = self.get_diameter_result_code(answer)
        exp_result_code = self.get_diameter_exp_result_code(answer)

        if result_code == resultcodes.DIAMETER_SUCCESS or exp_result_code in [resultcodes.DIAMETER_FIRST_REGISTRATION,
                                                                              resultcodes.DIAMETER_SUBSEQUENT_REGISTRATION]:
            registration_status = {}
            registration_status[JSON_RC] = result_code if result_code == resultcodes.DIAMETER_SUCCESS else exp_result_code

            server_name = self.cx.findFirstAVP(answer, "Server-Name")
            if server_name:
                registration_status[JSON_SCSCF] = server_name.getOctetString()
            else:
                server_capabilities = self.cx.findFirstAVP(answer, "Server-Capabilities")
                man_capabilities = []
                opt_capabilities = []
                if server_capabilities:
                    man_capabilities = [avp.getInteger32() for avp in self.cx.findAVP(server_capabilities, "Mandatory-Capability")]
                    opt_capabilities = [avp.getInteger32() for avp in self.cx.findAVP(server_capabilities, "Optional-Capability")]
                registration_status[JSON_MAN_CAP] = man_capabilities
                registration_status[JSON_OPT_CAP] = opt_capabilities
        elif exp_result_code in [resultcodes.DIAMETER_ERROR_USER_UNKNOWN, resultcodes.DIAMETER_ERROR_IDENTITIES_DONT_MATCH]:
            self.log_diameter_error(answer)
            raise UserNotIdentifiable()
        elif exp_result_code == resultcodes.DIAMETER_ERROR_ROAMING_NOT_ALLOWED or result_code == resultcodes.DIAMETER_AUTHORIZATION_REJECTED:
            self.log_diameter_error(answer)
            raise UserNotAuthorized()
        elif result_code == resultcodes.DIAMETER_TOO_BUSY:
            # If the error is an Overload response, increment the HSS penalty counter
            penaltycounter.incr_hss_penalty_count()
            self.log_diameter_error(answer)
            raise HSSOverloaded()
        else:
            # Translated into a 500 higher up the stack
            defer.returnValue(None)

        defer.returnValue(registration_status)
Пример #4
0
    def fetch_multimedia_auth(self, private_id, public_id, authtype, autn):
        if self.peer is None:
            raise HSSStillConnecting()
        if not self.peer.alive:
            raise HSSConnectionLost()
        _log.debug("Sending Multimedia-Auth request for %s/%s/%s/%s" % (private_id, public_id, authtype, autn))

        public_id = str(public_id)
        private_id = str(private_id)
        req = self.cx.getCommandRequest(self.peer.stack, "Multimedia-Auth", True)
        self.session_id += 1
        req.addAVP(self.cx.getAVP('Session-Id').withOctetString("%s;%u;%u" % (settings.PUBLIC_HOSTNAME, self.session_id >> 32, self.session_id & 0xffffffff)))
        req.addAVP(self.cx.getAVP('Auth-Session-State').withInteger32(1))
        req.addAVP(self.cx.getAVP('Destination-Realm').withOctetString(self.peer.realm))
        req.addAVP(self.cx.getAVP('Destination-Host').withOctetString(self.peer.identity))
        req.addAVP(self.cx.getAVP('User-Name').withOctetString(private_id))
        req.addAVP(self.cx.getAVP('Public-Identity').withOctetString(public_id))
        req.addAVP(self.cx.getAVP('Server-Name').withOctetString(self.server_name))
        req.addAVP(self.cx.getAVP('SIP-Number-Auth-Items').withInteger32(1))

        auth_avp = self.cx.getAVP('SIP-Auth-Data-Item')
        # Update the request depending on the authentication method
        if authtype == authtypes.AKA:
            auth_avp.addAVP(self.cx.getAVP('SIP-Authentication-Scheme').withOctetString('Digest-AKAv1-MD5'))
            if autn:
                auth_avp.addAVP(self.cx.getAVP('SIP-Authorization').withOctetString(autn))
        elif authtype == authtypes.SIP_DIGEST:
            auth_avp.addAVP(self.cx.getAVP('SIP-Authentication-Scheme').withOctetString('SIP Digest'))
        elif settings.LOWERCASE_UNKNOWN:
            auth_avp.addAVP(self.cx.getAVP('SIP-Authentication-Scheme').withOctetString('unknown'))
        else:
            auth_avp.addAVP(self.cx.getAVP('SIP-Authentication-Scheme').withOctetString('Unknown'))

        req.addAVP(auth_avp)

        # Send off message to HSS
        self.peer.stack.sendByPeer(self.peer, req)

        # Hook up our deferred to the callback
        d = defer.Deferred()
        self.app.add_pending_response(req, d)
        answer = yield d

        # Have response, get the authentication scheme from it
        scheme = self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item", "SIP-Authentication-Scheme")

        if scheme:
            if "SIP Digest" in scheme.getOctetString():
                digest = self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                              "SIP-Digest-Authenticate AVP", "Digest-HA1").getOctetString()
                realm = self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                             "SIP-Digest-Authenticate AVP", "Digest-Realm").getOctetString()

                # QoP is optional, so needs special handling
                qop_avp = self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                               "SIP-Digest-Authenticate AVP", "Digest-QoP")
                qop = None
                if qop_avp:
                    qop = qop_avp.getOctetString()

                if authtype == authtypes.UNKNOWN:
                    preferred = True
                else:
                    preferred = False

                auth = DigestAuthVector(digest, realm, qop, preferred)
                defer.returnValue(auth)
            elif "Digest-AKAv1-MD5" in scheme.getOctetString():
                # Integrity key and confidentiality key are "LDQUOT
                # *(HEXDIG) RDQUOT" as per TS 24.229 7.2A.1.2
                ck = hexlify(self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                          "Confidentiality-Key").getOctetString())
                ik = hexlify(self.cx.findFirstAVP(answer,
                                                  "SIP-Auth-Data-Item", "Integrity-Key").getOctetString())
                # The digest on the Authorization header is <"> 32LHEX
                # <"> as per RFC 2617 section 3.2.2
                response = hexlify(self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                                        "SIP-Authorization").getOctetString())
                # The nonce on the WWW-Authenticate header is base64
                # encoded as per RFC 3310 section 3.2.
                challenge = b64encode(self.cx.findFirstAVP(answer, "SIP-Auth-Data-Item",
                                                 "SIP-Authenticate").getOctetString())

                auth = AKAAuthVector(challenge, response, ck, ik)
                defer.returnValue(auth)
            else:
                _log.debug("Invalid authentication scheme: %s" % scheme.getOctetString())
                defer.returnValue(None)
        else:
            self.log_diameter_error(answer)
            # If the error is an Overload response, increment the HSS penalty counter
            if self.get_diameter_result_code(answer) == 3004:
                penaltycounter.incr_hss_penalty_count()
                raise HSSOverloaded()
            else:
                # Translated into a 404 higher up the stack
                defer.returnValue(None)