constraints_test.go
1 package macaroons_test 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/lightningnetwork/lnd/macaroons" 10 "github.com/stretchr/testify/require" 11 macaroon "gopkg.in/macaroon.v2" 12 ) 13 14 var ( 15 testRootKey = []byte("dummyRootKey") 16 testID = []byte("dummyId") 17 testLocation = "lnd" 18 testVersion = macaroon.LatestVersion 19 expectedTimeCaveatSubstring = fmt.Sprintf("time-before %d", time.Now().Year()) 20 ) 21 22 func createDummyMacaroon(t *testing.T) *macaroon.Macaroon { 23 dummyMacaroon, err := macaroon.New( 24 testRootKey, testID, testLocation, testVersion, 25 ) 26 require.NoError(t, err, "Error creating initial macaroon") 27 return dummyMacaroon 28 } 29 30 // TestAddConstraints tests that constraints can be added to an existing 31 // macaroon and therefore tighten its restrictions. 32 func TestAddConstraints(t *testing.T) { 33 t.Parallel() 34 35 // We need a dummy macaroon to start with. Create one without 36 // a bakery, because we mock everything anyway. 37 initialMac := createDummyMacaroon(t) 38 39 // Now add a constraint and make sure we have a cloned macaroon 40 // with the constraint applied instead of a mutated initial one. 41 newMac, err := macaroons.AddConstraints( 42 initialMac, macaroons.TimeoutConstraint(1), 43 ) 44 require.NoError(t, err, "Error adding constraint") 45 if &newMac == &initialMac { 46 t.Fatalf("Initial macaroon has been changed, something " + 47 "went wrong!") 48 } 49 50 // Finally, test that the constraint has been added. 51 if len(initialMac.Caveats()) == len(newMac.Caveats()) { 52 t.Fatalf("No caveat has been added to the macaroon when " + 53 "constraint was applied") 54 } 55 } 56 57 // TestTimeoutConstraint tests that a caveat for the lifetime of 58 // a macaroon is created. 59 func TestTimeoutConstraint(t *testing.T) { 60 t.Parallel() 61 62 // Get a configured version of the constraint function. 63 constraintFunc := macaroons.TimeoutConstraint(3) 64 65 // Now we need a dummy macaroon that we can apply the constraint 66 // function to. 67 testMacaroon := createDummyMacaroon(t) 68 err := constraintFunc(testMacaroon) 69 require.NoError(t, err, "Error applying timeout constraint") 70 71 // Finally, check that the created caveat has an 72 // acceptable value. 73 if !strings.HasPrefix( 74 string(testMacaroon.Caveats()[0].Id), 75 expectedTimeCaveatSubstring, 76 ) { 77 78 t.Fatalf("Added caveat '%s' does not meet the expectations!", 79 testMacaroon.Caveats()[0].Id) 80 } 81 } 82 83 // TestTimeoutConstraint tests that a caveat for the lifetime of 84 // a macaroon is created. 85 func TestIpLockConstraint(t *testing.T) { 86 t.Parallel() 87 88 // Get a configured version of the constraint function. 89 constraintFunc := macaroons.IPLockConstraint("127.0.0.1") 90 91 // Now we need a dummy macaroon that we can apply the constraint 92 // function to. 93 testMacaroon := createDummyMacaroon(t) 94 err := constraintFunc(testMacaroon) 95 require.NoError(t, err, "Error applying timeout constraint") 96 97 // Finally, check that the created caveat has an 98 // acceptable value. 99 if string(testMacaroon.Caveats()[0].Id) != "ipaddr 127.0.0.1" { 100 t.Fatalf("Added caveat '%s' does not meet the expectations!", 101 testMacaroon.Caveats()[0].Id) 102 } 103 } 104 105 // TestIPLockBadIP tests that an IP constraint cannot be added if the 106 // provided string is not a valid IP address. 107 func TestIPLockBadIP(t *testing.T) { 108 t.Parallel() 109 110 constraintFunc := macaroons.IPLockConstraint("127.0.0/800") 111 testMacaroon := createDummyMacaroon(t) 112 err := constraintFunc(testMacaroon) 113 if err == nil { 114 t.Fatalf("IPLockConstraint with bad IP should fail.") 115 } 116 } 117 118 // TestCustomConstraint tests that a custom constraint with a name and value can 119 // be added to a macaroon. 120 func TestCustomConstraint(t *testing.T) { 121 t.Parallel() 122 123 // Test a custom caveat with a value first. 124 constraintFunc := macaroons.CustomConstraint("unit-test", "test-value") 125 testMacaroon := createDummyMacaroon(t) 126 require.NoError(t, constraintFunc(testMacaroon)) 127 128 require.Equal( 129 t, []byte("lnd-custom unit-test test-value"), 130 testMacaroon.Caveats()[0].Id, 131 ) 132 require.True(t, macaroons.HasCustomCaveat(testMacaroon, "unit-test")) 133 require.False(t, macaroons.HasCustomCaveat(testMacaroon, "test-value")) 134 require.False(t, macaroons.HasCustomCaveat(testMacaroon, "something")) 135 require.False(t, macaroons.HasCustomCaveat(nil, "foo")) 136 137 customCaveatCondition := macaroons.GetCustomCaveatCondition( 138 testMacaroon, "unit-test", 139 ) 140 require.Equal(t, customCaveatCondition, "test-value") 141 142 // Custom caveats don't necessarily need a value, just the name is fine 143 // too to create a tagged macaroon. 144 constraintFunc = macaroons.CustomConstraint("unit-test", "") 145 testMacaroon = createDummyMacaroon(t) 146 require.NoError(t, constraintFunc(testMacaroon)) 147 148 require.Equal( 149 t, []byte("lnd-custom unit-test"), testMacaroon.Caveats()[0].Id, 150 ) 151 require.True(t, macaroons.HasCustomCaveat(testMacaroon, "unit-test")) 152 require.False(t, macaroons.HasCustomCaveat(testMacaroon, "test-value")) 153 require.False(t, macaroons.HasCustomCaveat(testMacaroon, "something")) 154 155 customCaveatCondition = macaroons.GetCustomCaveatCondition( 156 testMacaroon, "unit-test", 157 ) 158 require.Equal(t, customCaveatCondition, "") 159 }