Esempio n. 1
0
        def _log_in(self, client):
            """Emulates test client login in the store.

            Fill current session with `openid`, `macaroon_root` and
            `macaroon_discharge`.

            Return the expected `Authorization` header for further verification
            in API requests.
            """
            # Basic root/discharge macaroons pair.
            root = pymacaroons.Macaroon('test', 'testing', 'a_key')
            root.add_third_party_caveat('3rd', 'a_caveat-key', 'a_ident')
            discharge = pymacaroons.Macaroon('3rd', 'a_ident', 'a_caveat_key')

            with client.session_transaction() as s:
                s['openid'] = {
                    'image': None,
                    'nickname': 'Toto',
                    'fullname': 'El Toto',
                    'email': '*****@*****.**'
                }
                s['macaroon_root'] = root.serialize()
                s['macaroon_discharge'] = discharge.serialize()

            return get_authorization_header(
                root.serialize(), discharge.serialize())
Esempio n. 2
0
        def _log_in(self, client):
            """Emulates test client login in the store.

            Fill current session with `openid`, `macaroon_root` and
            `macaroon_discharge`.

            Return the expected `Authorization` header for further verification
            in API requests.
            """
            # Basic root/discharge macaroons pair.
            root = pymacaroons.Macaroon("test", "testing", "a_key")
            root.add_third_party_caveat("3rd", "a_caveat-key", "a_ident")
            discharge = pymacaroons.Macaroon("3rd", "a_ident", "a_caveat_key")

            with client.session_transaction() as s:
                s["publisher"] = {
                    "image": None,
                    "nickname": "Toto",
                    "fullname": "El Toto",
                    "email": "*****@*****.**",
                }
                s["macaroon_root"] = root.serialize()
                s["macaroon_discharge"] = discharge.serialize()

            return get_authorization_header(root.serialize(),
                                            discharge.serialize())
Esempio n. 3
0
    def test_extract_macaroons_from_request(self):
        def encode_macaroon(m):
            macaroons = '[' + utils.macaroon_to_json_string(m) + ']'
            return base64.urlsafe_b64encode(
                utils.to_bytes(macaroons)).decode('ascii')

        req = Request('http://example.com')
        m1 = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2,
                                  identifier='one')
        req.add_header('Macaroons', encode_macaroon(m1))
        m2 = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2,
                                  identifier='two')
        jar = requests.cookies.RequestsCookieJar()
        jar.set_cookie(
            utils.cookie(
                name='macaroon-auth',
                value=encode_macaroon(m2),
                url='http://example.com',
            ))
        jar.add_cookie_header(req)

        macaroons = httpbakery.extract_macaroons(req)
        self.assertEquals(len(macaroons), 2)
        macaroons.sort(key=lambda ms: ms[0].identifier)
        self.assertEquals(macaroons[0][0].identifier, m1.identifier)
        self.assertEquals(macaroons[1][0].identifier, m2.identifier)
Esempio n. 4
0
    def test_publisher_api_execption(self):
        snap_name = "test-snap"

        api_url = 'https://dashboard.snapcraft.io/dev/api/snaps/info/{}'
        api_url = api_url.format(
            snap_name
        )

        payload = {
            'error_list': [
                {
                    'code': 'user-not-ready',
                    'message': 'missing namespace'
                }
            ]
        }
        responses.add(
            responses.GET, api_url,
            json=payload, status=500)

        root = pymacaroons.Macaroon('test', 'testing', 'a_key')
        root.add_third_party_caveat('3rd', 'a_caveat-key', 'a_ident')
        discharge = pymacaroons.Macaroon('3rd', 'a_ident', 'a_caveat_key')

        with self.assertRaises(exceptions.MissingUsername):
            publisher_api.get_snap_info(
                'test-snap',
                {
                    'macaroon_root': root.serialize(),
                    'macaroon_discharge': discharge.serialize(),
                },
            )
Esempio n. 5
0
def create_macaroon():
    m = pymacaroons.Macaroon(location=SITE_LOCATION, identifier = str(uuid.uuid4()), key="secret1234")
    m.add_first_party_caveat("name:%s" % MACAROON_NAME)
    m.add_first_party_caveat("activity:DOWNLOAD")
    m.add_first_party_caveat("path:/store")
    m.add_first_party_caveat("before:2020-05-23T20:45:34Z")
    return m.serialize()
Esempio n. 6
0
    def test_get_user_from_macaroon_with_valid_duration(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id, ))
        macaroon.add_first_party_caveat("time < 900000000")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True

        user_info = yield self.auth.get_user_by_access_token(
            macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)
Esempio n. 7
0
 def raw_macaroon(self):
     return pymacaroons.Macaroon(
         location="fake location",
         identifier=str(uuid4()),
         key=b"fake key",
         version=pymacaroons.MACAROON_V2,
     ).serialize()
Esempio n. 8
0
    def test_get_user_from_macaroon(self):
        self.store.get_user_by_access_token = Mock(
            return_value=defer.succeed(
                {"name": "@baldrick:matrix.org", "device_id": "device"}
            )
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key,
        )
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
        user_info = yield defer.ensureDeferred(
            self.auth.get_user_by_access_token(macaroon.serialize())
        )
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)

        # TODO: device_id should come from the macaroon, but currently comes
        # from the db.
        self.assertEqual(user_info["device_id"], "device")
Esempio n. 9
0
 def test_invalid_discharge_raises_exception(self):
     conf = config.Config()
     conf.set('macaroon', pymacaroons.Macaroon().serialize())
     conf.set('unbound_discharge', 'inval*id')
     conf.save()
     with self.assertRaises(errors.InvalidCredentialsError):
         storeapi._macaroon_auth(conf)
Esempio n. 10
0
    def test_get_guest_user_from_macaroon(self):
        self.store.get_user_by_id = Mock(
            return_value=defer.succeed({"is_guest": True}))
        self.store.get_user_by_access_token = Mock(
            return_value=defer.succeed(None))

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key,
        )
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id, ))
        macaroon.add_first_party_caveat("guest = true")
        serialized = macaroon.serialize()

        user_info = yield defer.ensureDeferred(
            self.auth.get_user_by_access_token(serialized))
        user = user_info["user"]
        is_guest = user_info["is_guest"]
        self.assertEqual(UserID.from_string(user_id), user)
        self.assertTrue(is_guest)
        self.store.get_user_by_id.assert_called_with(user_id)
Esempio n. 11
0
    def acl(self, request):
        content_type = 'application/json'

        if 'packages' in request.json_body:
            packages = request.json_body['packages']
            unregistered_package = {
                'name': 'unregistered-snap-name',
                'series': '16',
            }
            if unregistered_package in packages:
                return response.Response(
                    json.dumps({
                        'error_message':
                        "Snap not found for the given snap "
                        "name: 'unregistered-snap-name' and "
                        "series: '16'",
                    }).encode(), 404, [('Content-Type', content_type)])

        permission = request.path.split('/')[-1]
        logger.debug('Handling ACL request for {}'.format(permission))
        sso_host = urllib.parse.urlparse(
            os.environ.get('UBUNTU_SSO_API_ROOT_URL',
                           "http://localhost")).netloc
        macaroon = pymacaroons.Macaroon(caveats=[
            pymacaroons.Caveat(caveat_id='test caveat',
                               location=sso_host,
                               verification_key_id='test verifiacion')
        ])
        payload = json.dumps({'macaroon': macaroon.serialize()}).encode()
        response_code = 200
        return response.Response(payload, response_code,
                                 [('Content-Type', content_type)])
Esempio n. 12
0
 def test_macaroon_ops_fatal_error(self):
     # When we get a non-VerificationError error from the
     # opstore, we don't do any more verification.
     checker = bakery.Checker(macaroon_opstore=_MacaroonStoreWithError())
     m = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2)
     with self.assertRaises(bakery.AuthInitError):
         checker.auth([m]).allow(test_context, [bakery.LOGIN_OP])
Esempio n. 13
0
    def create_macaroon(self, location, user_id, description, caveats):
        """
        Returns a tuple of a new raw (serialized) macaroon and its DB model.
        The description provided is not embedded into the macaroon, only stored
        in the DB model.
        """
        user = self.db.query(User).filter(User.id == user_id).one()

        # NOTE: This is a bit of a hack: we keep a separate copy of the
        # permissions caveat in the DB, so that we can display scope information
        # in the UI.
        permissions = next(c for c in caveats if "permissions" in c)  # pragma: no cover
        dm = Macaroon(
            user=user, description=description, permissions_caveat=permissions
        )
        self.db.add(dm)
        self.db.flush()

        m = pymacaroons.Macaroon(
            location=location,
            identifier=str(dm.id),
            key=dm.key,
            version=pymacaroons.MACAROON_V2,
        )
        for caveat in caveats:
            m.add_first_party_caveat(json.dumps(caveat))
        serialized_macaroon = f"pypi-{m.serialize()}"
        return serialized_macaroon, dm
Esempio n. 14
0
    def test_get_user_from_macaroon(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={
                "name": "@baldrick:matrix.org",
                "device_id": "device",
            }
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
        user_info = yield self.auth.get_user_by_access_token(macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)

        # TODO: device_id should come from the macaroon, but currently comes
        # from the db.
        self.assertEqual(user_info["device_id"], "device")
Esempio n. 15
0
    def test_get_user_from_macaroon_expired(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"})

        user = "******"
        macaroon = pymacaroons.Macaroon(location=self.hs.config.server_name,
                                        identifier="key",
                                        key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user, ))
        macaroon.add_first_party_caveat("time < 1")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True
        # yield self.auth.get_user_from_macaroon(macaroon.serialize())
        # TODO(daniel): Turn on the check that we validate expiration, when we
        # validate expiration (and remove the above line, which will start
        # throwing).
        with self.assertRaises(AuthError) as cm:
            yield self.auth.get_user_from_macaroon(macaroon.serialize())
        self.assertEqual(401, cm.exception.code)
        self.assertIn("Invalid macaroon", cm.exception.msg)
    def __init__(self,
                 root_key,
                 id,
                 location=None,
                 version=LATEST_VERSION,
                 namespace=None):
        '''Creates a new macaroon with the given root key, id and location.

        If the version is more than the latest known version,
        the latest known version will be used. The namespace should hold the
        namespace of the service that is creating the macaroon.
        @param root_key bytes or string
        @param id bytes or string
        @param location bytes or string
        @param version the bakery version.
        @param namespace is that of the service creating it
        '''
        if version > LATEST_VERSION:
            log.info('use last known version:{} instead of: {}'.format(
                LATEST_VERSION, version))
            version = LATEST_VERSION
        # m holds the underlying macaroon.
        self._macaroon = pymacaroons.Macaroon(
            location=location,
            key=root_key,
            identifier=id,
            version=macaroon_version(version))
        # version holds the version of the macaroon.
        self._version = version
        self._caveat_data = {}
        if namespace is None:
            namespace = checkers.Namespace()
        self._namespace = namespace
        self._caveat_id_prefix = bytearray()
Esempio n. 17
0
 def _generate_base_macaroon(self, user_id):
     macaroon = pymacaroons.Macaroon(location=self.server_name,
                                     identifier="key",
                                     key=self.macaroon_secret_key)
     macaroon.add_first_party_caveat("gen = 1")
     macaroon.add_first_party_caveat("user_id = %s" % (user_id, ))
     return macaroon
Esempio n. 18
0
 def test_json_unknown_version(self):
     m = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2)
     with self.assertRaises(ValueError) as exc:
         json.loads(json.dumps({
             'm': m.serialize(serializer=serializers.JsonSerializer()),
             'v': bakery.LATEST_VERSION + 1
         }), cls=bakery.MacaroonJSONDecoder)
     self.assertEqual('unknown bakery version 4', exc.exception.args[0])
Esempio n. 19
0
 def test_macaroon_to_dict(self):
     m = pymacaroons.Macaroon(
         key=b'rootkey', identifier=b'some id', location='here', version=2)
     as_dict = bakery.macaroon_to_dict(m)
     data = json.dumps(as_dict)
     m1 = pymacaroons.Macaroon.deserialize(data, json_serializer.JsonSerializer())
     self.assertEqual(m1.signature, m.signature)
     pymacaroons.Verifier().verify(m1, b'rootkey')
Esempio n. 20
0
 def _send_tokens_discharge(self, data):
     self.send_response(200)
     self.send_header('Content-Type', 'application/json')
     self.end_headers()
     response = {
         'discharge_macaroon': pymacaroons.Macaroon().serialize()
         }
     self.wfile.write(
         json.dumps(response).encode())
Esempio n. 21
0
 def _(**kwargs):
     defaults = {
         "location": "example.com",
         "identifier": "123foo",
         "key": "ohsosecret",
         "version": pymacaroons.MACAROON_V2,
     }
     defaults.update(kwargs)
     return pymacaroons.Macaroon(**defaults)
Esempio n. 22
0
	def test_wrong_location(self):
		fake_macaroon = pymacaroons.Macaroon(
				identifier=b"12345-67890",
				signature="4eba1dde2d0866f550278e40bb354542",
				location="github.com",
				version=pymacaroons.MACAROON_V2,
				)
		fake_macaroon.add_first_party_caveat(json.dumps({"permissions": {"projects": ["dict2css"]}, "version": 1}))

		assert validate_pypi_token(f"pypi-{fake_macaroon.serialize()}") == (False, "The token is not for PyPI.")
Esempio n. 23
0
 def test_json_inconsistent_version(self):
     m = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V1)
     with self.assertRaises(ValueError) as exc:
         json.loads(json.dumps({
             'm': json.loads(m.serialize(
                 serializer=serializers.JsonSerializer())),
             'v': bakery.LATEST_VERSION
         }), cls=bakery.MacaroonJSONDecoder)
     self.assertEqual('underlying macaroon has inconsistent version; '
                      'got 1 want 2', exc.exception.args[0])
Esempio n. 24
0
	def test_no_caveats(self):
		fake_macaroon = pymacaroons.Macaroon(
				identifier=b"12345-67890",
				signature="4eba1dde2d0866f550278e40bb354542",
				location="pypi.org",
				version=pymacaroons.MACAROON_V2,
				)

		error_msg = "The decoded output does not have the expected format."
		assert validate_pypi_token(f"pypi-{fake_macaroon.serialize()}") == (False, error_msg)
Esempio n. 25
0
	def test_seemingly_valid(self):
		fake_macaroon = pymacaroons.Macaroon(
				identifier=b"12345-67890",
				signature="4eba1dde2d0866f550278e40bb354542",
				location="pypi.org",
				version=pymacaroons.MACAROON_V2,
				)
		fake_macaroon.add_first_party_caveat(json.dumps({"permissions": {"projects": ["dict2css"]}, "version": 1}))

		assert validate_pypi_token(f"pypi-{fake_macaroon.serialize()}") == (True, '')
Esempio n. 26
0
 def _generate_base_macaroon(self,
                             type: MacaroonType) -> pymacaroons.Macaroon:
     macaroon = pymacaroons.Macaroon(
         location=self._location,
         identifier="key",
         key=self._secret_key,
     )
     macaroon.add_first_party_caveat("gen = 1")
     macaroon.add_first_party_caveat(f"type = {type}")
     return macaroon
Esempio n. 27
0
    def test_find_userid_invalid_macaroon(self, macaroon_service):
        raw_macaroon = pymacaroons.Macaroon(
            location="fake location",
            identifier=str(uuid4()),
            key=b"fake key",
            version=pymacaroons.MACAROON_V2,
        ).serialize()
        raw_macaroon = f"pypi-{raw_macaroon}"

        assert macaroon_service.find_userid(raw_macaroon) is None
Esempio n. 28
0
    def test_verify_unprefixed_macaroon(self, macaroon_service):
        raw_macaroon = pymacaroons.Macaroon(
            location="fake location",
            identifier=str(uuid4()),
            key=b"fake key",
            version=pymacaroons.MACAROON_V2,
        ).serialize()

        with pytest.raises(services.InvalidMacaroon):
            macaroon_service.verify(raw_macaroon, pretend.stub(),
                                    pretend.stub(), pretend.stub())
Esempio n. 29
0
 def _handle_acl_request(self, permission):
     logger.debug('Handling ACL request for {}'.format(permission))
     self.send_response(200)
     self.send_header('Content-Type', 'application/json')
     self.end_headers()
     macaroon = pymacaroons.Macaroon(caveats=[
         pymacaroons.Caveat(caveat_id='test caveat',
                            location='localhost',
                            verification_key_id='test verifiacion')
     ])
     response = {'macaroon': macaroon.serialize()}
     self.wfile.write(json.dumps(response).encode())
Esempio n. 30
0
    def test_publisher_api(self):
        snap_name = "test-snap"

        api_url = 'https://dashboard.snapcraft.io/dev/api/snaps/info/{}'
        api_url = api_url.format(
            snap_name
        )

        payload = {'api': 'yolo'}
        responses.add(
            responses.GET, api_url,
            json=payload, status=200)

        root = pymacaroons.Macaroon('test', 'testing', 'a_key')
        root.add_third_party_caveat('3rd', 'a_caveat-key', 'a_ident')
        discharge = pymacaroons.Macaroon('3rd', 'a_ident', 'a_caveat_key')
        response = publisher_api.get_snap_info('test-snap', {
            'macaroon_root': root.serialize(),
            'macaroon_discharge': discharge.serialize(),
        })

        self.assertEqual(payload, response)