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