Skip to content

Commit

Permalink
Some basic unit tests for version 1
Browse files Browse the repository at this point in the history
  • Loading branch information
rescrv committed Jul 26, 2016
1 parent d93f3b3 commit 2e511f1
Show file tree
Hide file tree
Showing 21 changed files with 476 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
/libtool
/ltmain.sh
/m4
/macaroon-test-runner
/Makefile
/Makefile.in
/missing
Expand Down
29 changes: 28 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ EXTRA_DIST += test/python-hmac-sanity-check.sh
EXTRA_DIST += test/readme.sh

check_LTLIBRARIES = libmacaroons-shim.la
check_PROGRAMS = test/varint
check_PROGRAMS =
check_PROGRAMS += test/varint
check_PROGRAMS += macaroon-test-runner

libmacaroons_shim_la_SOURCES = shim.c explicit_bzero.c
libmacaroons_shim_la_LDFLAGS = -module -avoid-version -rpath /evil/libtool/hack/to/force/shared/lib/creation
Expand All @@ -87,6 +89,22 @@ TESTS += test/varint
test_varint_SOURCES = test/varint.c varint.c
test_varint_CFLAGS = $(AM_CFLAGS) $(CFLAGS)

macaroon_test_runner_SOURCES = test/macaroon-test-runner.c base64.c
macaroon_test_runner_LDADD = libmacaroons.la
macaroon_test_runner_CFLAGS = $(AM_CFLAGS) $(CFLAGS)

macaroon_unit_test_stubs =
macaroon_unit_test_stubs += test/unit/caveat_v1_1.vtest.sh
macaroon_unit_test_stubs += test/unit/caveat_v1_2.vtest.sh
macaroon_unit_test_stubs += test/unit/caveat_v1_3.vtest.sh
macaroon_unit_test_stubs += test/unit/root_v1_1.vtest.sh
macaroon_unit_test_stubs += test/unit/root_v1_2.vtest.sh

TESTS += $(macaroon_unit_test_stubs)
check_SCRIPTS =
check_SCRIPTS += $(macaroon_unit_test_stubs)


#################################### Python ####################################

pyexec_LTLIBRARIES =
Expand All @@ -111,3 +129,12 @@ bindings_python_macaroons_la_LIBADD += $(PYTHON_LDFLAGS)
bindings_python_macaroons_la_LDFLAGS = -module -avoid-version -export-symbols-regex $(PYTHON_SYMBOL)macaroons $(AM_LDFLAGS) $(LDFLAGS)
bindings/python/macaroons.c: bindings/python/macaroons.pyx
$(pyx_verbose)cython bindings/python/macaroons.pyx

################################################################################
################################## Maintenance #################################
################################################################################

EXTRA_DIST += maint/generate-shell-stubs

maintainer-generate:
maint/generate-shell-stubs
4 changes: 2 additions & 2 deletions bindings/python/macaroons.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cdef extern from "macaroons.h":
void macaroon_signature(const macaroon* M, const unsigned char** signature, size_t* signature_sz)
size_t macaroon_serialize_size_hint(macaroon* M)
int macaroon_serialize(macaroon* M, char* data, size_t data_sz, macaroon_returncode* err)
macaroon* macaroon_deserialize(char* data, macaroon_returncode* err)
macaroon* macaroon_deserialize(unsigned char* data, size_t data_sz, macaroon_returncode* err)
size_t macaroon_inspect_size_hint(macaroon* M)
int macaroon_inspect(macaroon* M, char* data, size_t data_sz, macaroon_returncode* err)
macaroon* macaroon_copy(macaroon* M, macaroon_returncode* err)
Expand Down Expand Up @@ -344,7 +344,7 @@ def deserialize(m):
cdef Macaroon M = Macaroon()
cdef macaroon_returncode err
m = tobytes(m)
M._M = macaroon_deserialize(m, &err)
M._M = macaroon_deserialize(m, len(m), &err)
if M._M == NULL:
raise_error(err)
return M
72 changes: 72 additions & 0 deletions doc/tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
Tests
-----

The test/unit/ directory of the libmacaroons repo contains several tests of
the macaroons serialization, deserialization, and verifier. This document
describes the format of these language-independent test files so that all
macaroon implementations may validate themselves against the same tests.

Verification Tests
------------------

Verification tests test the verifier and for correctness. Each test is
contained within a single file that, by convention, ends in ".vtest". The
file describes the version of macaroons used by the test, whether the request
is authorized, the verifier, and the macaroons to be verified. The test file
is designed to be easy to parse in a variety of languages. A simple test
looks like:

# a simple test of a macaroon with an exact caveat verified with the correct
# root key and verifier
version 1
authorized
key this is the key
exact account = 3735928559
MDAyMWxvY2F0aW9uIGh0dHA6Ly9leGFtcGxlLm9yZy8KMDAxNWlkZW50aWZpZXIga2V5aWQKMDAxZGNpZCBhY2NvdW50ID0gMzczNTkyODU1OQowMDJmc2lnbmF0dXJlIPVIB_bcbt-Ivw9zBrOCJWKjYlM9v3M5umF2XaS9JZ2HCg

This test will construct a verifier that corresponds to this C code:

struct macaroon_verifier* V = macaroon_verifier_create();
macaroon_verifier_satisfy_exact(V, "account = 3735928559", 20, &err);

and then verify the single macaroon with:

macaroon_verify(V, M, "this is the key", 15, NULL, 0, &err);

The format of the file is intended to be pretty easy to interpret. It adheres
to the following rules (references to the C implementation should be mapped to
their equivalents in other implementations):

- Empty lines and lines beginning with a '#' are ignored; the remaining
bullets' description of line numbers assume no ignored lines
- The first line lists the version(s) the test requires of the
implementation. It starts with the literal "version " and then a
space-separated list of version numbers. A version number ending in "j"
indicates JSON format. Currently-supported versions are "1", "2", "2j".
- The second line indicates the outcome of the test. It must be either
"authorized" or "unauthorized"
- The third line provides the root secret for the macaroons tree. The line
starts with the literal "key " and then the key itself up to, but
excluding the '\n' that terminates the line. In the above example, the key
would be the literal "this is the key". The key is provided to the
function "macaroon_create" and not "macaroon_create_raw".
- The next 0 or more lines are caveats to be added to the verifier. Caveats
starting with the literal "exact " provide a predicate to be passed to the
function "macaroon_verifier_satisfy_exact". As with the key, the
predicate is the sequence of characters up to, but excluding the '\n' that
terminates the line. Caveats starting with the literal "general" followed
by any C-style identifier refer to a builtin general caveat. These caveats
are functions that match "macaroon_caveat_*" in the libmacaroons
implementation, where the wildcard is the identifier specified after the
literal "general".
- The remaining 1 or more lines are macaroons to be passed to the verifier.
The first of these macaroons corresponds to the "M" argument of the
"macaroon_verify" function and the remainder comprise the MS argument.
Each macaroon is base-64 encoded to avoid having to parse binary data from
the test file. The decoded form of the line corresponds to a macaroon in
one of the serialized formats specified in "version".

Serialization Tests
-------------------

XXX write these and some tests
43 changes: 41 additions & 2 deletions macaroons.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
#error bad constants
#endif

#define XSTR(x) #x
#define STR(x) XSTR(x)
#define STRINGIFY(x) case (x): return XSTR(x);

struct predicate
{
const unsigned char* data;
Expand All @@ -88,6 +92,26 @@ struct macaroon_verifier
size_t verifier_callbacks_cap;
};

MACAROON_API const char*
macaroon_error(enum macaroon_returncode err)
{
switch (err)
{
STRINGIFY(MACAROON_SUCCESS);
STRINGIFY(MACAROON_OUT_OF_MEMORY);
STRINGIFY(MACAROON_HASH_FAILED);
STRINGIFY(MACAROON_INVALID);
STRINGIFY(MACAROON_TOO_MANY_CAVEATS);
STRINGIFY(MACAROON_CYCLE);
STRINGIFY(MACAROON_BUF_TOO_SMALL);
STRINGIFY(MACAROON_NOT_AUTHORIZED);
STRINGIFY(MACAROON_NO_JSON_SUPPORT);
STRINGIFY(MACAROON_UNSUPPORTED_FORMAT);
default:
return "unknown error";
}
}

/* Allocate a new macaroon with space for "num_caveats" caveats and a body of
* "body_data" bytes. Returns via _ptr a contiguous set of "body_data" bytes to
* which the callee may write.
Expand Down Expand Up @@ -944,10 +968,25 @@ macaroon_serialize(const struct macaroon* M,
return macaroon_serialize_v1(M, data, data_sz, err);
}

static const char v1_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/-_";

MACAROON_API struct macaroon*
macaroon_deserialize(const char* data, enum macaroon_returncode* err)
macaroon_deserialize(const unsigned char* data, size_t data_sz,
enum macaroon_returncode* err)
{
return macaroon_deserialize_v1(data, err);
if (data_sz == 0)
{
*err = MACAROON_INVALID;
return NULL;
}

if (strchr(v1_chars, data[0]))
{
return macaroon_deserialize_v1((const char*)data, data_sz, err);
}

abort();

}

MACAROON_API size_t
Expand Down
6 changes: 5 additions & 1 deletion macaroons.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ enum macaroon_returncode
MACAROON_UNSUPPORTED_FORMAT=2057
};

const char*
macaroon_error(enum macaroon_returncode err);

/* Create a new macaroon.
* - location/location_sz is a hint to the target's location
* - key/key_sz is the key used as a secret for macaroon construction
Expand Down Expand Up @@ -183,7 +186,8 @@ macaroon_serialize(const struct macaroon* M,
enum macaroon_returncode* err);

struct macaroon*
macaroon_deserialize(const char* data, enum macaroon_returncode* err);
macaroon_deserialize(const unsigned char* data, size_t data_sz,
enum macaroon_returncode* err);

/* Human-readable representation *FOR DEBUGGING ONLY* */
size_t
Expand Down
15 changes: 15 additions & 0 deletions maint/generate-shell-stubs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env python3

import glob
import stat
import os

for x in glob.glob('test/unit/*.vtest'):
fname = x + '.sh'
f = open(fname, 'w')
f.write('''#!/bin/sh
exec macaroon-test-runner < {0}
'''.format(x))
f.flush()
f.close()
os.chmod(fname, stat.S_IRWXU)
1 change: 1 addition & 0 deletions test/env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export MACAROONS_VERSION="$3"

export LD_PRELOAD="${MACAROONS_BUILDDIR}/.libs/libmacaroons-shim.so"
export PYTHONPATH="${MACAROONS_BUILDDIR}"/bindings/python/.libs:${PYTHONPATH}
export PATH=${MACAROONS_BUILDDIR}:${MACAROONS_SRCDIR}:${PATH}
Loading

0 comments on commit 2e511f1

Please sign in to comment.