def get_discharge(ctx, cav, payload):
     checker = common.ThirdPartyCheckerWithCaveats([
         checkers.declared_caveat('foo', 'a'),
         checkers.declared_caveat('arble', 'b')
     ])
     return macaroonbakery.discharge(ctx, cav.caveat_id_bytes, payload,
                                     third_party.oven.key, checker,
                                     third_party.oven.locator)
示例#2
0
 def check_third_party_caveat(self, ctx, cav_info):
     if cav_info.condition == b'x':
         return [checkers.declared_caveat('foo', 'fooval1')]
     if cav_info.condition == b'y':
         return [
             checkers.declared_caveat('foo', 'fooval2'),
             checkers.declared_caveat('baz', 'bazval')
         ]
     raise common.ThirdPartyCaveatCheckFailed('not matched')
        def get_discharge(ctx, cav, payload):
            checker = common.ThirdPartyCheckerWithCaveats([
                checkers.declared_caveat('foo', 'a'),
                checkers.declared_caveat('arble', 'b'),
            ])

            # Sneaky client adds a first party caveat.
            m = macaroonbakery.discharge(ctx, cav.caveat_id_bytes, payload,
                                         third_party.oven.key, checker,
                                         third_party.oven.locator)
            m.add_caveat(checkers.declared_caveat('foo', 'c'), None, None)
            return m
 def get_discharge(cav, payload):
     checker = common.ThirdPartyCheckerWithCaveats([
         checkers.declared_caveat('foo', 'a'),
         checkers.declared_caveat('arble', 'b')
     ])
     return bakery.discharge(
         common.test_context,
         cav.caveat_id_bytes,
         payload,
         third_party.oven.key,
         checker,
         third_party.oven.locator,
     )
        def get_discharge(cav, payload):
            checker = common.ThirdPartyCheckerWithCaveats([
                checkers.declared_caveat('foo', 'a'),
                checkers.declared_caveat('arble', 'b'),
            ])

            # Sneaky client adds a first party caveat.
            m = bakery.discharge(
                common.test_context, cav.caveat_id_bytes,
                payload,
                third_party.oven.key, checker,
                third_party.oven.locator,
            )
            m.add_caveat(checkers.declared_caveat('foo', 'c'), None, None)
            return m
    def check_third_party_caveat(self, ctx, info):
        if info.condition != 'is-authenticated-user':
            raise bakery.CaveatNotRecognizedError(
                'third party condition not recognized')

        username = ctx.get(_DISCHARGE_USER_KEY, '')
        if username == '':
            raise bakery.ThirdPartyCaveatCheckFailed('no current user')
        self._test._discharges.append(
            _DischargeRecord(location=self._location, user=username))
        return [checkers.declared_caveat('username', username)]
示例#7
0
    def check_third_party_caveat(self, ctx, info):
        if info.condition != 'is-authenticated-user':
            raise bakery.CaveatNotRecognizedError(
                'third party condition not recognized')

        username = ctx.get(_DISCHARGE_USER_KEY, '')
        if username == '':
            raise bakery.ThirdPartyCaveatCheckFailed('no current user')
        self._test._discharges.append(
            _DischargeRecord(location=self._location, user=username))
        return [checkers.declared_caveat('username', username)]
def _check_need_declared(ctx, cav_info, checker):
    arg = cav_info.condition.decode('utf-8')
    i = arg.find(' ')
    if i <= 0:
        raise macaroonbakery.VerificationError(
            'need-declared caveat requires an argument, got %q'.format(arg))
    need_declared = arg[0:i].split(',')
    for d in need_declared:
        if d == '':
            raise macaroonbakery.VerificationError('need-declared caveat with '
                                                   'empty required attribute')
    if len(need_declared) == 0:
        raise macaroonbakery.VerificationError('need-declared caveat with no '
                                               'required attributes')
    cav_info = cav_info._replace(condition=arg[i + 1:].encode('utf-8'))
    caveats = checker.check_third_party_caveat(ctx, cav_info)
    declared = {}
    for cav in caveats:
        if cav.location is not None and cav.location != '':
            continue
        # Note that we ignore the error. We allow the service to
        # generate caveats that we don't understand here.
        try:
            cond, arg = checkers.parse_caveat(cav.condition)
        except ValueError:
            continue
        if cond != checkers.COND_DECLARED:
            continue
        parts = arg.split()
        if len(parts) != 2:
            raise macaroonbakery.VerificationError('declared caveat has no '
                                                   'value')
        declared[parts[0]] = True
    # Add empty declarations for everything mentioned in need-declared
    # that was not actually declared.
    for d in need_declared:
        if not declared.get(d, False):
            caveats.append(checkers.declared_caveat(d, ''))
    return caveats
def _check_need_declared(ctx, cav_info, checker):
    arg = cav_info.condition.decode('utf-8')
    i = arg.find(' ')
    if i <= 0:
        raise bakery.VerificationError(
            'need-declared caveat requires an argument, got %q'.format(arg),
        )
    need_declared = arg[0:i].split(',')
    for d in need_declared:
        if d == '':
            raise bakery.VerificationError('need-declared caveat with empty required attribute')
    if len(need_declared) == 0:
        raise bakery.VerificationError('need-declared caveat with no required attributes')
    cav_info = cav_info._replace(condition=arg[i + 1:].encode('utf-8'))
    caveats = checker.check_third_party_caveat(ctx, cav_info)
    declared = {}
    for cav in caveats:
        if cav.location is not None and cav.location != '':
            continue
        # Note that we ignore the error. We allow the service to
        # generate caveats that we don't understand here.
        try:
            cond, arg = checkers.parse_caveat(cav.condition)
        except ValueError:
            continue
        if cond != checkers.COND_DECLARED:
            continue
        parts = arg.split()
        if len(parts) != 2:
            raise bakery.VerificationError('declared caveat has no value')
        declared[parts[0]] = True
    # Add empty declarations for everything mentioned in need-declared
    # that was not actually declared.
    for d in need_declared:
        if not declared.get(d, False):
            caveats.append(checkers.declared_caveat(d, ''))
    return caveats
    def test_first_party_caveat_squashing(self):
        locator = _DischargerLocator()
        ids = _IdService('ids', locator, self)
        auth = _OpAuthorizer({
            bakery.Op(entity='e1', action='read'): {'alice'},
            bakery.Op(entity='e2', action='read'): {'alice'},
        })
        ts = _Service('myservice', auth, ids, locator)
        tests = [
            ('duplicates removed', [
                checkers.Caveat(condition='true 1', namespace='testns'),
                checkers.Caveat(condition='true 2', namespace='testns'),
                checkers.Caveat(condition='true 1', namespace='testns'),
                checkers.Caveat(condition='true 1', namespace='testns'),
                checkers.Caveat(condition='true 3', namespace='testns'),
            ], [
                checkers.Caveat(condition='true 1', namespace='testns'),
                checkers.Caveat(condition='true 2', namespace='testns'),
                checkers.Caveat(condition='true 3', namespace='testns'),
            ]), ('earliest time before', [
                checkers.time_before_caveat(epoch + timedelta(days=1)),
                checkers.Caveat(condition='true 1', namespace='testns'),
                checkers.time_before_caveat(
                    epoch + timedelta(days=0, hours=1)),
                checkers.time_before_caveat(epoch + timedelta(
                    days=0, hours=0, minutes=5)),
            ], [
                checkers.time_before_caveat(epoch + timedelta(
                    days=0, hours=0, minutes=5)),
                checkers.Caveat(condition='true 1', namespace='testns'),
            ]), ('operations and declared caveats removed', [
                checkers.deny_caveat(['foo']),
                checkers.allow_caveat(['read', 'write']),
                checkers.declared_caveat('username', 'bob'),
                checkers.Caveat(condition='true 1', namespace='testns'),
            ], [
                checkers.Caveat(condition='true 1', namespace='testns'),
            ])
        ]
        for test in tests:
            print(test[0])

            # Make a first macaroon with all the required first party caveats.
            ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'alice')
            m1 = _Client(locator).capability(
                ctx, ts, [bakery.Op(entity='e1', action='read')])
            m1.add_caveats(test[1], None, None)

            # Make a second macaroon that's not used to check that it's
            # caveats are not added.
            m2 = _Client(locator).capability(
                ctx, ts, [bakery.Op(entity='e1', action='read')])
            m2.add_caveat(checkers.Caveat(
                condition='true notused', namespace='testns'), None, None)
            client = _Client(locator)
            client.add_macaroon(ts, 'authz1', [m1.macaroon])
            client.add_macaroon(ts, 'authz2', [m2.macaroon])

            m3 = client.capability(
                test_context, ts, [bakery.Op(entity='e1', action='read')])
            self.assertEqual(
                _macaroon_conditions(m3.macaroon.caveats, False),
                _resolve_caveats(m3.namespace, test[2]))
    def test_first_party_caveat_squashing(self):
        locator = _DischargerLocator()
        ids = _IdService('ids', locator, self)
        auth = _OpAuthorizer({
            macaroonbakery.Op(entity='e1', action='read'): {'alice'},
            macaroonbakery.Op(entity='e2', action='read'): {'alice'},
        })
        ts = _Service('myservice', auth, ids, locator)
        tests = [('duplicates removed', [
            checkers.Caveat(condition='true 1', namespace='testns'),
            checkers.Caveat(condition='true 2', namespace='testns'),
            checkers.Caveat(condition='true 1', namespace='testns'),
            checkers.Caveat(condition='true 1', namespace='testns'),
            checkers.Caveat(condition='true 3', namespace='testns'),
        ], [
            checkers.Caveat(condition='true 1', namespace='testns'),
            checkers.Caveat(condition='true 2', namespace='testns'),
            checkers.Caveat(condition='true 3', namespace='testns'),
        ]),
                 ('earliest time before', [
                     checkers.time_before_caveat(epoch + timedelta(days=1)),
                     checkers.Caveat(condition='true 1', namespace='testns'),
                     checkers.time_before_caveat(epoch +
                                                 timedelta(days=0, hours=1)),
                     checkers.time_before_caveat(
                         epoch + timedelta(days=0, hours=0, minutes=5)),
                 ], [
                     checkers.time_before_caveat(
                         epoch + timedelta(days=0, hours=0, minutes=5)),
                     checkers.Caveat(condition='true 1', namespace='testns'),
                 ]),
                 ('operations and declared caveats removed', [
                     checkers.deny_caveat(['foo']),
                     checkers.allow_caveat(['read', 'write']),
                     checkers.declared_caveat('username', 'bob'),
                     checkers.Caveat(condition='true 1', namespace='testns'),
                 ], [
                     checkers.Caveat(condition='true 1', namespace='testns'),
                 ])]
        for test in tests:
            print(test[0])

            # Make a first macaroon with all the required first party caveats.
            ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'alice')
            m1 = _Client(locator).capability(
                ctx, ts, [macaroonbakery.Op(entity='e1', action='read')])
            m1.add_caveats(test[1], None, None)

            # Make a second macaroon that's not used to check that it's
            # caveats are not added.
            m2 = _Client(locator).capability(
                ctx, ts, [macaroonbakery.Op(entity='e1', action='read')])
            m2.add_caveat(
                checkers.Caveat(condition='true notused', namespace='testns'),
                None, None)
            client = _Client(locator)
            client.add_macaroon(ts, 'authz1', [m1.macaroon])
            client.add_macaroon(ts, 'authz2', [m2.macaroon])

            m3 = client.capability(
                test_context, ts,
                [macaroonbakery.Op(entity='e1', action='read')])
            self.assertEqual(_macaroon_conditions(m3.macaroon.caveats, False),
                             _resolve_caveats(m3.namespace, test[2]))
    def test_checkers(self):

        tests = [
            ('nothing in context, no extra checkers', [
                ('something',
                 'caveat "something" not satisfied: caveat not recognized'),
                ('', 'cannot parse caveat "": empty caveat'),
                (' hello', 'cannot parse caveat " hello": caveat starts with'
                           ' space character'),
            ], None),
            ('one failed caveat', [
                ('t:a aval', None),
                ('t:b bval', None),
                ('t:a wrong', 'caveat "t:a wrong" not satisfied: wrong arg'),
            ], None),
            ('time from clock', [
                (checkers.time_before_caveat(
                    datetime.utcnow() +
                    timedelta(0, 1)).condition,
                 None),
                (checkers.time_before_caveat(NOW).condition,
                 'caveat "time-before 2006-01-02T15:04:05.000123Z" '
                 'not satisfied: macaroon has expired'),
                (checkers.time_before_caveat(NOW - timedelta(0, 1)).condition,
                 'caveat "time-before 2006-01-02T15:04:04.000123Z" '
                 'not satisfied: macaroon has expired'),
                ('time-before bad-date',
                 'caveat "time-before bad-date" not satisfied: '
                 'cannot parse "bad-date" as RFC 3339'),
                (checkers.time_before_caveat(NOW).condition + " ",
                 'caveat "time-before 2006-01-02T15:04:05.000123Z " '
                 'not satisfied: '
                 'cannot parse "2006-01-02T15:04:05.000123Z " as RFC 3339'),
            ], lambda x: checkers.context_with_clock(ctx, TestClock())),
            ('real time', [
                (checkers.time_before_caveat(datetime(
                    year=2010, month=1, day=1)).condition,
                 'caveat "time-before 2010-01-01T00:00:00.000000Z" not '
                 'satisfied: macaroon has expired'),
                (checkers.time_before_caveat(datetime(
                    year=3000, month=1, day=1)).condition, None),
            ], None),
            ('declared, no entries', [
                (checkers.declared_caveat('a', 'aval').condition,
                 'caveat "declared a aval" not satisfied: got a=null, '
                 'expected "aval"'),
                (checkers.COND_DECLARED, 'caveat "declared" not satisfied: '
                                         'declared caveat has no value'),
            ], None),
            ('declared, some entries', [
                (checkers.declared_caveat('a', 'aval').condition, None),
                (checkers.declared_caveat('b', 'bval').condition, None),
                (checkers.declared_caveat('spc', ' a b').condition, None),
                (checkers.declared_caveat('a', 'bval').condition,
                 'caveat "declared a bval" not satisfied: '
                 'got a="aval", expected "bval"'),
                (checkers.declared_caveat('a', ' aval').condition,
                 'caveat "declared a  aval" not satisfied: '
                 'got a="aval", expected " aval"'),
                (checkers.declared_caveat('spc', 'a b').condition,
                 'caveat "declared spc a b" not satisfied: '
                 'got spc=" a b", expected "a b"'),
                (checkers.declared_caveat('', 'a b').condition,
                 'caveat "error invalid caveat \'declared\' key """ '
                 'not satisfied: bad caveat'),
                (checkers.declared_caveat('a b', 'a b').condition,
                 'caveat "error invalid caveat \'declared\' key "a b"" '
                 'not satisfied: bad caveat'),
            ], lambda x: checkers.context_with_declared(x, {
                'a': 'aval',
                'b': 'bval',
                'spc': ' a b'})),
        ]
        checker = checkers.Checker()
        checker.namespace().register('testns', 't')
        checker.register('a', 'testns', arg_checker(self, 't:a', 'aval'))
        checker.register('b', 'testns', arg_checker(self, 't:b', 'bval'))
        ctx = checkers.AuthContext()
        for test in tests:
            print(test[0])
            if test[2] is not None:
                ctx1 = test[2](ctx)
            else:
                ctx1 = ctx
            for check in test[1]:
                err = checker.check_first_party_caveat(ctx1, check[0])
                if check[1] is not None:
                    self.assertEqual(err, check[1])
                else:
                    self.assertIsNone(err)
 def test_infer_declared(self):
     tests = [
         ('no macaroons', [], {}, None),
         ('single macaroon with one declaration', [
             [checkers.Caveat(condition='declared foo bar')]
         ], {'foo': 'bar'}, None),
         ('only one argument to declared', [
             [checkers.Caveat(condition='declared foo')]
         ], {}, None),
         ('spaces in value', [
             [checkers.Caveat(condition='declared foo bar bloggs')]
         ], {'foo': 'bar bloggs'}, None),
         ('attribute with declared prefix', [
             [checkers.Caveat(condition='declaredccf foo')]
         ], {}, None),
         ('several macaroons with different declares', [
             [
                 checkers.declared_caveat('a', 'aval'),
                 checkers.declared_caveat('b', 'bval')
             ], [
                 checkers.declared_caveat('c', 'cval'),
                 checkers.declared_caveat('d', 'dval')
             ]
         ], {'a': 'aval', 'b': 'bval', 'c': 'cval', 'd': 'dval'}, None),
         ('duplicate values', [
             [
                 checkers.declared_caveat('a', 'aval'),
                 checkers.declared_caveat('a', 'aval'),
                 checkers.declared_caveat('b', 'bval')
             ], [
                 checkers.declared_caveat('a', 'aval'),
                 checkers.declared_caveat('b', 'bval'),
                 checkers.declared_caveat('c', 'cval'),
                 checkers.declared_caveat('d', 'dval')
             ]
         ], {'a': 'aval', 'b': 'bval', 'c': 'cval', 'd': 'dval'}, None),
         ('conflicting values', [
             [
                 checkers.declared_caveat('a', 'aval'),
                 checkers.declared_caveat('a', 'conflict'),
                 checkers.declared_caveat('b', 'bval')
             ], [
                 checkers.declared_caveat('a', 'conflict'),
                 checkers.declared_caveat('b', 'another conflict'),
                 checkers.declared_caveat('c', 'cval'),
                 checkers.declared_caveat('d', 'dval')
             ]
         ], {'c': 'cval', 'd': 'dval'}, None),
         ('third party caveats ignored', [
             [checkers.Caveat(condition='declared a no conflict',
                              location='location')],
             [checkers.declared_caveat('a', 'aval')]
         ], {'a': 'aval'}, None),
         ('unparseable caveats ignored', [
             [checkers.Caveat(condition=' bad')],
             [checkers.declared_caveat('a', 'aval')]
         ], {'a': 'aval'}, None),
         ('infer with namespace', [
             [
                 checkers.declared_caveat('a', 'aval'),
                 caveat_with_ns(checkers.declared_caveat('a', 'aval'),
                                'testns'),
             ]
         ], {'a': 'aval'}, None),
     ]
     for test in tests:
         uri_to_prefix = test[3]
         if uri_to_prefix is None:
             uri_to_prefix = {checkers.STD_NAMESPACE: ''}
         ns = checkers.Namespace(uri_to_prefix)
         print(test[0])
         ms = []
         for i, caveats in enumerate(test[1]):
             m = Macaroon(key=None, identifier=six.int2byte(i), location='',
                          version=MACAROON_V2)
             for cav in caveats:
                 cav = ns.resolve_caveat(cav)
                 if cav.location == '':
                     m.add_first_party_caveat(cav.condition)
                 else:
                     m.add_third_party_caveat(cav.location, None,
                                              cav.condition)
             ms.append(m)
         self.assertEqual(checkers.infer_declared(ms), test[2])
示例#14
0
    def test_checkers(self):

        tests = [
            ('nothing in context, no extra checkers', [
                ('something',
                 'caveat "something" not satisfied: caveat not recognized'),
                ('', 'cannot parse caveat "": empty caveat'),
                (' hello', 'cannot parse caveat " hello": caveat starts with'
                 ' space character'),
            ], None),
            ('one failed caveat', [
                ('t:a aval', None),
                ('t:b bval', None),
                ('t:a wrong', 'caveat "t:a wrong" not satisfied: wrong arg'),
            ], None),
            ('time from clock', [
                (checkers.time_before_caveat(datetime.utcnow() +
                                             timedelta(0, 1)).condition, None),
                (checkers.time_before_caveat(NOW).condition,
                 'caveat "time-before 2006-01-02T15:04:05.000123Z" '
                 'not satisfied: macaroon has expired'),
                (checkers.time_before_caveat(NOW - timedelta(0, 1)).condition,
                 'caveat "time-before 2006-01-02T15:04:04.000123Z" '
                 'not satisfied: macaroon has expired'),
                ('time-before bad-date',
                 'caveat "time-before bad-date" not satisfied: '
                 'cannot parse "bad-date" as RFC 3339'),
                (checkers.time_before_caveat(NOW).condition + " ",
                 'caveat "time-before 2006-01-02T15:04:05.000123Z " '
                 'not satisfied: '
                 'cannot parse "2006-01-02T15:04:05.000123Z " as RFC 3339'),
            ], lambda x: checkers.context_with_clock(ctx, TestClock())),
            ('real time', [
                (checkers.time_before_caveat(
                    datetime(year=2010, month=1, day=1)).condition,
                 'caveat "time-before 2010-01-01T00:00:00.000000Z" not '
                 'satisfied: macaroon has expired'),
                (checkers.time_before_caveat(
                    datetime(year=3000, month=1, day=1)).condition, None),
            ], None),
            ('declared, no entries', [
                (checkers.declared_caveat('a', 'aval').condition,
                 'caveat "declared a aval" not satisfied: got a=null, '
                 'expected "aval"'),
                (checkers.COND_DECLARED, 'caveat "declared" not satisfied: '
                 'declared caveat has no value'),
            ], None),
            ('declared, some entries', [
                (checkers.declared_caveat('a', 'aval').condition, None),
                (checkers.declared_caveat('b', 'bval').condition, None),
                (checkers.declared_caveat('spc', ' a b').condition, None),
                (checkers.declared_caveat('a', 'bval').condition,
                 'caveat "declared a bval" not satisfied: '
                 'got a="aval", expected "bval"'),
                (checkers.declared_caveat('a', ' aval').condition,
                 'caveat "declared a  aval" not satisfied: '
                 'got a="aval", expected " aval"'),
                (checkers.declared_caveat('spc', 'a b').condition,
                 'caveat "declared spc a b" not satisfied: '
                 'got spc=" a b", expected "a b"'),
                (checkers.declared_caveat('', 'a b').condition,
                 'caveat "error invalid caveat \'declared\' key """ '
                 'not satisfied: bad caveat'),
                (checkers.declared_caveat('a b', 'a b').condition,
                 'caveat "error invalid caveat \'declared\' key "a b"" '
                 'not satisfied: bad caveat'),
            ],
             lambda x: checkers.context_with_declared(x, {
                 'a': 'aval',
                 'b': 'bval',
                 'spc': ' a b'
             })),
        ]
        checker = checkers.Checker()
        checker.namespace().register('testns', 't')
        checker.register('a', 'testns', arg_checker(self, 't:a', 'aval'))
        checker.register('b', 'testns', arg_checker(self, 't:b', 'bval'))
        ctx = checkers.AuthContext()
        for test in tests:
            print(test[0])
            if test[2] is not None:
                ctx1 = test[2](ctx)
            else:
                ctx1 = ctx
            for check in test[1]:
                err = checker.check_first_party_caveat(ctx1, check[0])
                if check[1] is not None:
                    self.assertEqual(err, check[1])
                else:
                    self.assertIsNone(err)
示例#15
0
 def test_infer_declared(self):
     tests = [
         ('no macaroons', [], {}, None),
         ('single macaroon with one declaration',
          [[checkers.Caveat(condition='declared foo bar')]], {
              'foo': 'bar'
          }, None),
         ('only one argument to declared',
          [[checkers.Caveat(condition='declared foo')]], {}, None),
         ('spaces in value',
          [[checkers.Caveat(condition='declared foo bar bloggs')]], {
              'foo': 'bar bloggs'
          }, None),
         ('attribute with declared prefix',
          [[checkers.Caveat(condition='declaredccf foo')]], {}, None),
         ('several macaroons with different declares',
          [[
              checkers.declared_caveat('a', 'aval'),
              checkers.declared_caveat('b', 'bval')
          ],
           [
               checkers.declared_caveat('c', 'cval'),
               checkers.declared_caveat('d', 'dval')
           ]], {
               'a': 'aval',
               'b': 'bval',
               'c': 'cval',
               'd': 'dval'
           }, None),
         ('duplicate values', [[
             checkers.declared_caveat('a', 'aval'),
             checkers.declared_caveat('a', 'aval'),
             checkers.declared_caveat('b', 'bval')
         ],
                               [
                                   checkers.declared_caveat('a', 'aval'),
                                   checkers.declared_caveat('b', 'bval'),
                                   checkers.declared_caveat('c', 'cval'),
                                   checkers.declared_caveat('d', 'dval')
                               ]], {
                                   'a': 'aval',
                                   'b': 'bval',
                                   'c': 'cval',
                                   'd': 'dval'
                               }, None),
         ('conflicting values',
          [[
              checkers.declared_caveat('a', 'aval'),
              checkers.declared_caveat('a', 'conflict'),
              checkers.declared_caveat('b', 'bval')
          ],
           [
               checkers.declared_caveat('a', 'conflict'),
               checkers.declared_caveat('b', 'another conflict'),
               checkers.declared_caveat('c', 'cval'),
               checkers.declared_caveat('d', 'dval')
           ]], {
               'c': 'cval',
               'd': 'dval'
           }, None),
         ('third party caveats ignored', [[
             checkers.Caveat(condition='declared a no conflict',
                             location='location')
         ], [checkers.declared_caveat('a', 'aval')]], {
             'a': 'aval'
         }, None),
         ('unparseable caveats ignored',
          [[checkers.Caveat(condition=' bad')],
           [checkers.declared_caveat('a', 'aval')]], {
               'a': 'aval'
           }, None),
         ('infer with namespace', [[
             checkers.declared_caveat('a', 'aval'),
             caveat_with_ns(checkers.declared_caveat('a', 'aval'),
                            'testns'),
         ]], {
             'a': 'aval'
         }, None),
     ]
     for test in tests:
         uri_to_prefix = test[3]
         if uri_to_prefix is None:
             uri_to_prefix = {checkers.STD_NAMESPACE: ''}
         ns = checkers.Namespace(uri_to_prefix)
         print(test[0])
         ms = []
         for i, caveats in enumerate(test[1]):
             m = Macaroon(key=None,
                          identifier=six.int2byte(i),
                          location='',
                          version=MACAROON_V2)
             for cav in caveats:
                 cav = ns.resolve_caveat(cav)
                 if cav.location == '':
                     m.add_first_party_caveat(cav.condition)
                 else:
                     m.add_third_party_caveat(cav.location, None,
                                              cav.condition)
             ms.append(m)
         self.assertEqual(checkers.infer_declared(ms), test[2])