Exemplo n.º 1
0
    def get_initial_syncsession_data_for_request(self):

        # fetch a nonce value to use in creating the syncsession
        response = self.client.post(reverse('nonces-list'), {}, format='json')
        nonce = json.loads(response.content.decode())["id"]

        # prepare the data to send in the syncsession creation request
        data = {
            "id":
            uuid.uuid4().hex,
            "server_certificate_id":
            self.root_cert1_with_key.id,
            "client_certificate_id":
            self.sub_subset_cert1_with_key.id,
            "certificate_chain":
            json.dumps(
                CertificateSerializer(
                    self.sub_subset_cert1_with_key.get_ancestors(
                        include_self=True),
                    many=True).data),
            "connection_path":
            "http://127.0.0.1:8000",
            "instance":
            json.dumps(
                InstanceIDSerializer(
                    InstanceIDModel.get_or_create_current_instance()[0]).data),
            "nonce":
            nonce,
        }

        # sign the nonce/ID combo to attach to the request
        data["signature"] = self.sub_subset_cert1_with_key.sign(
            "{nonce}:{id}".format(**data))

        return data
Exemplo n.º 2
0
    def create_sync_session(self, client_cert, server_cert):
        # if server cert does not exist locally, retrieve it from server
        if not Certificate.objects.filter(id=server_cert.id).exists():
            self._get_certificate_chain(server_cert)

        # request the server for a one-time-use nonce
        nonce_resp = self._request(api_urls.NONCE, method="POST")
        nonce = json.loads(nonce_resp.content.decode())["id"]

        # if no hostname then url is actually an ip
        url = urlparse(self.base_url)
        hostname = url.hostname or self.base_url
        port = url.port or (80 if url.scheme == 'http' else 443)
        # prepare the data to send in the syncsession creation request
        data = {
            "id": uuid.uuid4().hex,
            "server_certificate_id": server_cert.id,
            "client_certificate_id": client_cert.id,
            "profile": client_cert.profile,
            "certificate_chain": json.dumps(CertificateSerializer(client_cert.get_ancestors(include_self=True), many=True).data),
            "connection_path": self.base_url,
            "instance": json.dumps(InstanceIDSerializer(InstanceIDModel.get_or_create_current_instance()[0]).data),
            "nonce": nonce,
            "client_ip": _get_client_ip_for_server(hostname, port),
            "server_ip": _get_server_ip(hostname),
        }

        # sign the nonce/ID combo to attach to the request
        message = "{nonce}:{id}".format(**data)
        data["signature"] = client_cert.sign(message)

        # Sync Session creation request
        session_resp = self._request(api_urls.SYNCSESSION, method="POST", data=data)

        # check that the nonce/id were properly signed by the server cert
        if not server_cert.verify(message, session_resp.json().get("signature")):
            raise CertificateSignatureInvalid()

        # build the data to be used for creating our own syncsession
        data = {
            "id": data['id'],
            "start_timestamp": timezone.now(),
            "last_activity_timestamp": timezone.now(),
            "active": True,
            "is_server": False,
            "client_certificate": client_cert,
            "server_certificate": server_cert,
            "profile": client_cert.profile,
            "connection_kind": "network",
            "connection_path": self.base_url,
            "client_ip": data['client_ip'],
            "server_ip": data['server_ip'],
            "client_instance": json.dumps(InstanceIDSerializer(InstanceIDModel.get_or_create_current_instance()[0]).data),
            "server_instance": session_resp.json().get("server_instance") or "{}",
        }
        sync_session = SyncSession.objects.create(**data)

        return SyncClient(self, sync_session)
Exemplo n.º 3
0
    def test_get_remote_certs(self):
        # mock certs being returned by server
        certs = self.subset_cert.get_ancestors(include_self=True)
        cert_serialized = json.dumps(
            CertificateSerializer(certs, many=True).data)
        NetworkSyncConnection._request.return_value.json.return_value = json.loads(
            cert_serialized)

        # we want to see if the models are created (not saved) successfully
        remote_certs = self.network_connection.get_remote_certificates('abc')
        self.assertSetEqual(set(certs), set(remote_certs))
Exemplo n.º 4
0
    def test_syncsession_creation_fails_with_client_cert_not_matching_cert_chain(
            self):

        data = self.get_initial_syncsession_data_for_request()

        data["certificate_chain"] = json.dumps(
            CertificateSerializer(
                self.subset_cert2_with_key.get_ancestors(include_self=True),
                many=True).data)

        self.assertSyncSessionCreationFails(data)
Exemplo n.º 5
0
    def test_get_cert_chain(self):
        # mock a cert chain being returned by server
        certs = self.subset_cert.get_ancestors(include_self=True)
        original_cert_count = certs.count()
        cert_serialized = json.dumps(
            CertificateSerializer(certs, many=True).data)
        NetworkSyncConnection._request.return_value.json.return_value = json.loads(
            cert_serialized)
        Certificate.objects.all().delete()

        # we only want to make sure the cert chain is saved
        self.network_connection._get_certificate_chain(certs[1])
        self.assertEqual(Certificate.objects.count(), original_cert_count)
Exemplo n.º 6
0
    def create_syncsession(self,
                           client_certificate=None,
                           server_certificate=None):

        if not client_certificate:
            client_certificate = self.sub_subset_cert1_with_key

        if not server_certificate:
            server_certificate = self.root_cert1_with_key

        # fetch a nonce value to use in creating the syncsession
        response = self.client.post(reverse('nonces-list'), {}, format='json')
        nonce = json.loads(response.content.decode())["id"]

        # prepare the data to send in the syncsession creation request
        data = {
            "id":
            uuid.uuid4().hex,
            "server_certificate_id":
            server_certificate.id,
            "client_certificate_id":
            client_certificate.id,
            "profile":
            client_certificate.profile,
            "certificate_chain":
            json.dumps(
                CertificateSerializer(
                    client_certificate.get_ancestors(include_self=True),
                    many=True).data),
            "connection_path":
            "http://127.0.0.1:8000",
            "instance":
            json.dumps(
                InstanceIDSerializer(
                    InstanceIDModel.get_or_create_current_instance()[0]).data),
            "nonce":
            nonce,
        }

        # sign the nonce/ID combo to attach to the request
        data["signature"] = client_certificate.sign(
            "{nonce}:{id}".format(**data))

        # make the API call to create the SyncSession
        response = self.client.post(reverse('syncsessions-list'),
                                    data,
                                    format='json')
        self.assertEqual(response.status_code, 201)

        return SyncSession.objects.get(id=data["id"])
Exemplo n.º 7
0
    def test_certificate_chain_pushing_fails_for_public_key(self):
        # do not use shared public key value
        self.unsaved_subset_cert.public_key = Key()
        self.unsaved_subset_cert.id = self.unsaved_subset_cert.calculate_uuid()
        self.unsaved_root_cert.sign_certificate(self.unsaved_subset_cert)

        # push cert chain up to server
        data = json.dumps(
            CertificateSerializer(
                [self.unsaved_root_cert, self.unsaved_subset_cert],
                many=True).data)
        response = self.client.post(reverse('certificatechain-list'),
                                    data=data,
                                    format='json')
        self.assertEqual(response.status_code, 400)
Exemplo n.º 8
0
    def test_certificate_chain_pushing_fails_for_nonce(self):
        # use non-existent nonce value
        self.unsaved_subset_cert.salt = uuid.uuid4().hex
        self.unsaved_subset_cert.id = self.unsaved_subset_cert.calculate_uuid()
        self.unsaved_root_cert.sign_certificate(self.unsaved_subset_cert)

        # push cert chain up to server
        data = json.dumps(
            CertificateSerializer(
                [self.unsaved_root_cert, self.unsaved_subset_cert],
                many=True).data)
        response = self.client.post(reverse('certificatechain-list'),
                                    data=data,
                                    format='json')
        self.assertEqual(response.status_code, 403)
Exemplo n.º 9
0
    def test_csr(self):
        # mock a "signed" cert being returned by server
        cert_serialized = json.dumps(
            CertificateSerializer(self.subset_cert).data)
        NetworkSyncConnection._request.return_value.json.return_value = json.loads(
            cert_serialized)
        self.subset_cert.delete()

        # we only want to make sure the "signed" cert is saved
        with mock.patch.object(Key,
                               "get_private_key_string",
                               return_value=self.subset_cert.private_key.
                               get_private_key_string()):
            self.network_connection.certificate_signing_request(
                self.root_cert, '', '')
        self.assertTrue(
            Certificate.objects.filter(
                id=json.loads(cert_serialized)['id']).exists())
Exemplo n.º 10
0
    def push_signed_client_certificate_chain(self, local_parent_cert,
                                             scope_definition_id,
                                             scope_params):
        if ALLOW_CERTIFICATE_PUSHING not in self.capabilities:
            raise MorangoServerDoesNotAllowNewCertPush(
                "Server does not allow certificate pushing")

        # grab shared public key of server
        publickey_response = self._get_public_key()

        # request the server for a one-time-use nonce
        nonce_response = self._get_nonce()

        # build up data for csr
        certificate = Certificate(
            parent_id=local_parent_cert.id,
            profile=local_parent_cert.profile,
            scope_definition_id=scope_definition_id,
            scope_version=local_parent_cert.scope_version,
            scope_params=json.dumps(scope_params),
            public_key=Key(
                public_key_string=publickey_response.json()[0]["public_key"]),
            salt=nonce_response.json()
            ["id"],  # for pushing signed certs, we use nonce as salt
        )

        # add ID and signature to the certificate
        certificate.id = certificate.calculate_uuid()
        certificate.parent.sign_certificate(certificate)

        # serialize the chain for sending to server
        certificate_chain = list(
            local_parent_cert.get_ancestors(
                include_self=True)) + [certificate]
        data = json.dumps(
            CertificateSerializer(certificate_chain, many=True).data)

        # client sends signed certificate chain to server
        self._push_certificate_chain(data)

        # if there are no errors, we can save the pushed certificate
        certificate.save()
        return certificate
Exemplo n.º 11
0
def registerfacility(token, facility):

    # request the server for a one-time-use nonce
    PORTAL_URL = conf.OPTIONS["Urls"]["DATA_PORTAL_SYNCING_BASE_URL"]
    response = requests.post(urljoin(PORTAL_URL, NONCE))
    response.raise_for_status()
    server_nonce = response.json()["id"]

    # get owned certificate for this facility
    client_cert = (facility.dataset.get_owned_certificates().filter(
        scope_definition_id=FULL_FACILITY).first())

    if client_cert is None:
        raise Certificate.DoesNotExist

    # build up data for request
    data = {
        "facility_id":
        facility.id,
        "server_nonce":
        server_nonce,
        "client_certificate_id":
        client_cert.id,
        "certificate_chain":
        json.dumps(
            CertificateSerializer(client_cert.get_ancestors(include_self=True),
                                  many=True).data),
        "token":
        token,
    }

    # sign the server nonce to attach to the request
    message = "{server_nonce}".format(**data)
    data["signature"] = client_cert.sign(message)

    # attempt to claim the facility
    response = requests.post(urljoin(PORTAL_URL,
                                     "portal/api/public/v1/registerfacility/"),
                             data=data)
    response.raise_for_status()
    return response
Exemplo n.º 12
0
    def test_certificate_chain_pushing(self):
        # attach nonce value to certificate salt
        response = self.client.post(reverse('nonces-list'), format='json')
        self.unsaved_subset_cert.salt = response.json()['id']
        self.unsaved_subset_cert.id = self.unsaved_subset_cert.calculate_uuid()
        self.unsaved_root_cert.sign_certificate(self.unsaved_subset_cert)

        # push cert chain up to server
        data = json.dumps(
            CertificateSerializer(
                [self.unsaved_root_cert, self.unsaved_subset_cert],
                many=True).data)
        response = self.client.post(reverse('certificatechain-list'),
                                    data=data,
                                    format='json')
        self.assertEqual(response.status_code, 201)
        saved_subset_cert = Certificate.objects.get(
            id=self.unsaved_subset_cert.id)
        self.assertEqual(
            saved_subset_cert.private_key.get_private_key_string(),
            self.sharedkey.private_key.get_private_key_string())
Exemplo n.º 13
0
    def push_signed_client_certificate_chain(self, local_parent_cert,
                                             scope_definition_id,
                                             scope_params):
        # grab shared public key of server
        publickey_response = self._get_public_key()

        # request the server for a one-time-use nonce
        nonce_response = self._get_nonce()

        # build up data for csr
        certificate = Certificate(
            parent_id=local_parent_cert.id,
            profile=local_parent_cert.profile,
            scope_definition_id=scope_definition_id,
            scope_version=local_parent_cert.scope_version,
            scope_params=json.dumps(scope_params),
            public_key=Key(
                public_key_string=publickey_response.json()[0]['public_key']),
            salt=nonce_response.json()[
                "id"]  # for pushing signed certs, we use nonce as salt
        )

        # add ID and signature to the certificate
        certificate.id = certificate.calculate_uuid()
        certificate.parent.sign_certificate(certificate)

        # serialize the chain for sending to server
        certificate_chain = list(
            local_parent_cert.get_descendants(
                include_self=True)) + [certificate]
        data = json.dumps(
            CertificateSerializer(certificate_chain, many=True).data)

        # client sends signed certificate chain to server
        self._push_certificate_chain(data)

        # if there are no errors, we can save the pushed certificate
        certificate.save()
        return certificate
Exemplo n.º 14
0
    def create_sync_session(self, client_cert, server_cert, chunk_size=500):
        # if server cert does not exist locally, retrieve it from server
        if not Certificate.objects.filter(id=server_cert.id).exists():
            cert_chain_response = self._get_certificate_chain(
                params={"ancestors_of": server_cert.id})

            # upon receiving cert chain from server, we attempt to save the chain into our records
            Certificate.save_certificate_chain(cert_chain_response.json(),
                                               expected_last_id=server_cert.id)

        # request the server for a one-time-use nonce
        nonce_resp = self._get_nonce()
        nonce = nonce_resp.json()["id"]

        # if no hostname then url is actually an ip
        url = urlparse(self.base_url)
        hostname = url.hostname or self.base_url
        port = url.port or (80 if url.scheme == "http" else 443)

        # prepare the data to send in the syncsession creation request
        data = {
            "id":
            uuid.uuid4().hex,
            "server_certificate_id":
            server_cert.id,
            "client_certificate_id":
            client_cert.id,
            "profile":
            client_cert.profile,
            "certificate_chain":
            json.dumps(
                CertificateSerializer(
                    client_cert.get_ancestors(include_self=True),
                    many=True).data),
            "connection_path":
            self.base_url,
            "instance":
            json.dumps(
                InstanceIDSerializer(
                    InstanceIDModel.get_or_create_current_instance()[0]).data),
            "nonce":
            nonce,
            "client_ip":
            _get_client_ip_for_server(hostname, port),
            "server_ip":
            _get_server_ip(hostname),
        }

        # sign the nonce/ID combo to attach to the request
        message = "{nonce}:{id}".format(**data)
        data["signature"] = client_cert.sign(message)

        # Sync Session creation request
        session_resp = self._create_sync_session(data)

        # check that the nonce/id were properly signed by the server cert
        if not server_cert.verify(message,
                                  session_resp.json().get("signature")):
            raise CertificateSignatureInvalid()

        # build the data to be used for creating our own syncsession
        data = {
            "id":
            data["id"],
            "start_timestamp":
            timezone.now(),
            "last_activity_timestamp":
            timezone.now(),
            "active":
            True,
            "is_server":
            False,
            "client_certificate":
            client_cert,
            "server_certificate":
            server_cert,
            "profile":
            client_cert.profile,
            "connection_kind":
            "network",
            "connection_path":
            self.base_url,
            "client_ip":
            data["client_ip"],
            "server_ip":
            data["server_ip"],
            "client_instance":
            json.dumps(
                InstanceIDSerializer(
                    InstanceIDModel.get_or_create_current_instance()[0]).data),
            "server_instance":
            session_resp.json().get("server_instance") or "{}",
        }
        sync_session = SyncSession.objects.create(**data)
        return SyncSessionClient(self, sync_session, chunk_size=chunk_size)