Esempio n. 1
0
    def test_verify_of_baked_image(self):
        url = 'https://example.org/beths-robotics-badge.json'
        png_badge = os.path.join(os.path.dirname(__file__), 'testfiles',
                                 'public_domain_heart.png')
        responses.add(responses.GET,
                      url,
                      body=test_components['2_0_basic_assertion'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')
        responses.add(responses.GET,
                      'https://w3id.org/openbadges/v2',
                      body=test_components['openbadges_context'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/robotics-badge.json',
                      body=test_components['2_0_basic_badgeclass'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/robotics-badge.png')
        responses.add(responses.GET,
                      'https://example.org/organization.json',
                      body=test_components['2_0_basic_issuer'],
                      status=200,
                      content_type='application/ld+json')

        with open(png_badge, 'rb') as image:
            baked_image = bake(image, test_components['2_0_basic_assertion'])
            responses.add(responses.GET,
                          'https://example.org/baked',
                          body=baked_image.read(),
                          content_type='image/png')
            results = verify(baked_image)

        # verify gets the JSON out of the baked image, and then detect_input_type
        # will reach out to the assertion URL to fetch the canonical assertion (thus,
        # we expect this to become an URL input type for the verifier).
        self.assertNotEqual(results, None)
        self.assertEqual(results.get('input').get('value'), url)
        self.assertEqual(results.get('input').get('input_type'), 'url')
        self.assertEqual(len(results['report']['messages']), 0,
                         "There should be no failing tasks.")

        # Verify that the same result occurs when passing in the baked image url.
        another_result = verify('https://example.org/baked')
        self.assertTrue(another_result['report']['valid'])
        self.assertEqual(another_result['report']['validationSubject'],
                         results['report']['validationSubject'])
Esempio n. 2
0
    def test_verify_function(self):
        url = 'https://example.org/beths-robotics-badge.json'
        responses.add(responses.GET,
                      url,
                      body=test_components['2_0_basic_assertion'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock('https://example.org/beths-robot-badge.png')
        responses.add(responses.GET,
                      'https://w3id.org/openbadges/v2',
                      body=test_components['openbadges_context'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/robotics-badge.json',
                      body=test_components['2_0_basic_badgeclass'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/robotics-badge.png')
        responses.add(responses.GET,
                      'https://example.org/organization.json',
                      body=test_components['2_0_basic_issuer'],
                      status=200,
                      content_type='application/ld+json')

        results = verify(url)
        self.assertEqual(results.get('input').get('value'), url)
        self.assertEqual(results.get('input').get('input_type'), 'url')

        self.assertEqual(len(results['report']['messages']), 0,
                         "There should be no failing tasks.")
Esempio n. 3
0
    def test_verify_with_original_json(self):
        url = 'https://example.org/beths-robotics-badge.json'
        responses.add(responses.GET,
                      url,
                      body=test_components['2_0_basic_assertion'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://w3id.org/openbadges/v2',
                      body=test_components['openbadges_context'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/robotics-badge.json',
                      body=test_components['2_0_basic_badgeclass'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/organization.json',
                      body=test_components['2_0_basic_issuer'],
                      status=200,
                      content_type='application/ld+json')

        result = verify(url, include_original_json=True)
        self.assertIn('original_json', list(result['input'].keys()))
        self.assertEqual(len(result['input']['original_json']), 3)
        self.assertIn(url, list(result['input']['original_json'].keys()))
Esempio n. 4
0
    def test_can_full_verify_with_revocation_check(self):
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])
        set_up_image_mock(input_badgeclass['image'])

        revocation_list = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': 'http://example.org/revocationList',
            'type': 'RevocationList',
            'revokedAssertions': []}
        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['revocationList'] = revocation_list['id']
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        private_key = RSA.generate(2048)
        print("PKEY")
        print(private_key.publickey().exportKey('PEM').decode())
        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': private_key.publickey().exportKey('PEM').decode()
        }

        set_up_context_mock()
        for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        header = json.dumps({'alg': 'RS256'})
        payload = json.dumps(input_assertion)

        encoded_separator = '.'
        if not sys.version[:3] < '3':
            encoded_separator = '.'.encode()
            encoded_header = b64encode(header.encode())
            encoded_payload = b64encode(payload.encode())
        else:
            encoded_header = b64encode(header)
            encoded_payload = b64encode(payload)

        signature = encoded_separator.join([
            encoded_header,
            encoded_payload,
            jws.sign(header, payload, private_key, is_json=True)
        ])

        response = verify(signature, use_cache=False)

        self.assertTrue(response['report']['valid'])
Esempio n. 5
0
    def test_verify_redirected_validation_subject(self):
        url = 'https://example.org/beths-robotics-badge.json'
        assertion_data = json.loads(test_components['2_0_basic_assertion'])
        alt_assertion_url = 'http://example.org/altbadgeurl'
        assertion_data['id'] = alt_assertion_url
        responses.add(responses.GET,
                      url,
                      json=assertion_data,
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      alt_assertion_url,
                      json=assertion_data,
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock('https://example.org/beths-robot-badge.png')
        responses.add(responses.GET,
                      'https://w3id.org/openbadges/v2',
                      body=test_components['openbadges_context'],
                      status=200,
                      content_type='application/ld+json')
        responses.add(responses.GET,
                      'https://example.org/robotics-badge.json',
                      body=test_components['2_0_basic_badgeclass'],
                      status=200,
                      content_type='application/ld+json')
        set_up_image_mock(u'https://example.org/robotics-badge.png')
        responses.add(responses.GET,
                      'https://example.org/organization.json',
                      body=test_components['2_0_basic_issuer'],
                      status=200,
                      content_type='application/ld+json')

        results = verify(url)

        self.assertEqual(len(results['report']['messages']), 1,
                         "There should be a warning about the redirection.")
        self.assertIn('Node fetched from source',
                      results['report']['messages'][0]['result'],
                      "Message should be the one about the graph ID change.")
        self.assertEqual(len(results['graph']), 3)
        assertion_node = [
            n for n in results['graph'] if n['id'] == assertion_data['id']
        ][0]
        self.assertEqual(assertion_node['badge'],
                         'https://example.org/robotics-badge.json')
        self.assertEqual(results['report']['validationSubject'],
                         alt_assertion_url)
    def test_revoked_badge_marked_invalid(self):
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])

        revocation_list = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': 'http://example.org/revocationList',
            'type': 'RevocationList',
            'revokedAssertions': [
                {'id': input_assertion['id'], 'revocationReason': 'A good reason, for sure'},
                {'id': 'urn:uuid:52e4c6b3-8c13-4fa8-8482-a5cf34ef37a9'},
                'urn:uuid:6deb4a00-ebce-4b28-8cc2-afa705ef7be4'
            ]
        }
        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['revocationList'] = revocation_list['id']
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        key = RSA.generate(2048)
        public_key_pem = key.publickey().export_key()

        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': public_key_pem.decode()
        }

        set_up_context_mock()
        for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        signature = jws.sign(input_assertion, key, algorithm='RS256')

        response = verify(signature, use_cache=False)
        self.assertFalse(response['report']['valid'])
        msg = [a for a in response['report']['messages'] if a.get('name') == VERIFY_SIGNED_ASSERTION_NOT_REVOKED][0]
        self.assertIn('A good reason', msg['result'])

        # Assert pruning went well to eliminate revocationlist revokedAssertions except for the revoked one
        rev_list = [n for n in response['graph'] if n.get('id') == revocation_list['id']][0]
        self.assertEqual(len(rev_list['revokedAssertions']), 1)
        self.assertEqual(rev_list['revokedAssertions'], [revocation_list['revokedAssertions'][0]])
    def test_upgrade_1_1_issuer_in_full_verify_with_redirect(self):
        setUpContextCache()
        old_url = "http://example.org/oldissuerurl"
        data = {
            "@context": "https://w3id.org/openbadges/v1",
            "type": "Issuer",
            "id": "http://example.org/realissuerurl",
            "description": "Example Badge Issuer",
            "url": "http://example.org",
            "email": "*****@*****.**",
            "name": "Test Issuer",
            "image": "http://example.org/image"
        }

        responses.add(responses.GET, old_url, json=data)
        responses.add(responses.GET, data['id'], json=data)

        result = verify(old_url)
        self.assertTrue(result['report']['valid'])
    def test_can_full_verify_jws_signed_assertion(self):
        """
        I can input a JWS string
        I can extract the Assertion from the input signature string and store it as the canonical version of the Assertion.
        I can discover and retrieve key information from the Assertion.
        I can Access the signing key
        I can verify the key is associated with the listed issuer Profile
        I can verify the JWS signature has been created by a key trusted to correspond to the issuer Profile
        Next: I can verify an assertion with an ephemeral embedded badgeclass as well
        """
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])
        set_up_image_mock(input_badgeclass['image'])

        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        key = RSA.generate(2048)
        public_key_pem = key.publickey().export_key()

        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': public_key_pem.decode()
        }

        set_up_context_mock()
        for doc in [input_badgeclass, input_issuer, cryptographic_key_doc]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        signature = jws.sign(input_assertion, key, algorithm='RS256')

        response = verify(signature, use_cache=False)

        self.assertTrue(response['report']['valid'])
    def test_can_full_verify_with_revocation_check(self):
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])
        set_up_image_mock(input_badgeclass['image'])

        revocation_list = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': 'http://example.org/revocationList',
            'type': 'RevocationList',
            'revokedAssertions': []}
        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['revocationList'] = revocation_list['id']
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        key = RSA.generate(2048)
        public_key_pem = key.publickey().export_key()

        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': public_key_pem.decode()
        }

        set_up_context_mock()
        for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        header = {'alg': 'RS256'}
        payload = json.dumps(input_assertion).encode()
        signature = jws.sign(input_assertion, key, algorithm='RS256')

        response = verify(signature, use_cache=False)

        self.assertTrue(response['report']['valid'])
Esempio n. 10
0
    def test_revoked_badge_marked_invalid(self):
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])

        revocation_list = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': 'http://example.org/revocationList',
            'type': 'RevocationList',
            'revokedAssertions': [
                {'id': input_assertion['id'], 'revocationReason': 'A good reason, for sure'},
                {'id': 'urn:uuid:52e4c6b3-8c13-4fa8-8482-a5cf34ef37a9'},
                'urn:uuid:6deb4a00-ebce-4b28-8cc2-afa705ef7be4'
            ]
        }
        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['revocationList'] = revocation_list['id']
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        private_key = RSA.generate(2048)
        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': make_string_from_bytes(private_key.publickey().exportKey('PEM'))
        }

        set_up_context_mock()
        for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        header = json.dumps({'alg': 'RS256'})
        payload = json.dumps(input_assertion)

        encoded_separator = '.'
        if not sys.version[:3] < '3':
            encoded_separator = '.'.encode()
            encoded_header = b64encode(header.encode())
            encoded_payload = b64encode(payload.encode())
        else:
            encoded_header = b64encode(header)
            encoded_payload = b64encode(payload)

        signature = encoded_separator.join([
            encoded_header,
            encoded_payload,
            jws.sign(header, payload, private_key, is_json=True)
        ])


        response = verify(signature, use_cache=False)
        self.assertFalse(response['report']['valid'])
        msg = [a for a in response['report']['messages'] if a.get('name') == VERIFY_SIGNED_ASSERTION_NOT_REVOKED][0]
        self.assertIn('A good reason', msg['result'])

        # Assert pruning went well to eliminate revocationlist revokedAssertions except for the revoked one
        rev_list = [n for n in response['graph'] if n.get('id') == revocation_list['id']][0]
        self.assertEqual(len(rev_list['revokedAssertions']), 1)
        self.assertEqual(rev_list['revokedAssertions'], [revocation_list['revokedAssertions'][0]])
Esempio n. 11
0
    def test_can_full_verify_jws_signed_assertion(self):
        """
        I can input a JWS string
        I can extract the Assertion from the input signature string and store it as the canonical version of the Assertion.
        I can discover and retrieve key information from the Assertion.
        I can Access the signing key
        I can verify the key is associated with the listed issuer Profile
        I can verify the JWS signature has been created by a key trusted to correspond to the issuer Profile
        Next: I can verify an assertion with an ephemeral embedded badgeclass as well
        """
        input_assertion = json.loads(test_components['2_0_basic_assertion'])
        input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'}
        set_up_image_mock(u'https://example.org/beths-robot-badge.png')

        input_badgeclass = json.loads(test_components['2_0_basic_badgeclass'])
        set_up_image_mock(input_badgeclass['image'])

        input_issuer = json.loads(test_components['2_0_basic_issuer'])
        input_issuer['publicKey'] = input_assertion['verification']['creator']

        private_key = RSA.generate(2048)

        cryptographic_key_doc = {
            '@context': OPENBADGES_CONTEXT_V2_URI,
            'id': input_assertion['verification']['creator'],
            'type': 'CryptographicKey',
            'owner': input_issuer['id'],
            'publicKeyPem': private_key.publickey().exportKey('PEM').decode()
        }

        set_up_context_mock()
        for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc]:
            responses.add(responses.GET, doc['id'], json=doc, status=200)

        header = json.dumps({'alg': 'RS256'})
        payload = json.dumps(input_assertion)



        encoded_separator = '.'
        if not sys.version[:3] < '3':
            encoded_separator = '.'.encode()
            encoded_header = b64encode(header.encode())
            encoded_payload = b64encode(payload.encode())
        else:
            encoded_header = b64encode(header)
            encoded_payload = b64encode(payload)

        signature = encoded_separator.join([
            encoded_header,
            encoded_payload,
            jws.sign(header,payload,private_key, is_json=True)
        ])


        response = verify(signature, use_cache=False)

        print("TEST CAN FULLY VERIFY JWS SIGNED ASSERTION : response:")
        print(response['report'])

        self.assertTrue(response['report']['valid'])