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())
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)
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)
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)