Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 1 | package security |
| 2 | |
| 3 | import ( |
| 4 | "io/ioutil" |
| 5 | "os" |
| 6 | "runtime" |
| 7 | "testing" |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 8 | |
Jiri Simsa | 519c507 | 2014-09-17 21:37:57 -0700 | [diff] [blame] | 9 | "veyron.io/veyron/veyron2/security" |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 10 | ) |
| 11 | |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 12 | func saveACLToTempFile(acl security.ACL) string { |
| 13 | f, err := ioutil.TempFile("", "saved_acl") |
| 14 | if err != nil { |
| 15 | panic(err) |
| 16 | } |
| 17 | defer f.Close() |
Tilak Sharma | d6ade0e | 2014-08-20 16:28:32 -0700 | [diff] [blame] | 18 | if err := SaveACL(f, acl); err != nil { |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 19 | defer os.Remove(f.Name()) |
| 20 | panic(err) |
| 21 | } |
| 22 | return f.Name() |
| 23 | } |
| 24 | |
| 25 | func updateACLInFile(fileName string, acl security.ACL) { |
| 26 | f, err := os.OpenFile(fileName, os.O_WRONLY, 0600) |
| 27 | if err != nil { |
| 28 | panic(err) |
| 29 | } |
| 30 | defer f.Close() |
Tilak Sharma | d6ade0e | 2014-08-20 16:28:32 -0700 | [diff] [blame] | 31 | if err := SaveACL(f, acl); err != nil { |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 32 | panic(err) |
| 33 | } |
| 34 | } |
| 35 | |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 36 | func testSelfRPCs(t *testing.T, authorizer security.Authorizer) { |
| 37 | _, file, line, _ := runtime.Caller(1) |
| 38 | var ( |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 39 | pserver, server = newPrincipal("server") |
| 40 | _, imposter = newPrincipal("server") |
| 41 | palice, alice = newPrincipal("alice") |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 42 | aliceServer = bless(palice, pserver, alice, "server") |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 43 | |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 44 | ctxp = &security.ContextParams{LocalPrincipal: pserver, LocalBlessings: server} |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 45 | tests = []struct { |
| 46 | remote security.Blessings |
| 47 | isAuthorized bool |
| 48 | }{ |
| 49 | {server, true}, |
| 50 | {imposter, false}, |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 51 | // A principal talking to itself (even if with a different blessing) is authorized. |
| 52 | // TODO(ashankar,ataly): Is this a desired property? |
| 53 | {aliceServer, true}, |
| 54 | } |
| 55 | ) |
| 56 | for _, test := range tests { |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 57 | ctxp.RemoteBlessings = test.remote |
| 58 | ctx := security.NewContext(ctxp) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 59 | if got, want := authorizer.Authorize(ctx), test.isAuthorized; (got == nil) != want { |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 60 | t.Errorf("%s:%d: %+v.Authorize(%v) returned error: %v, want error: %v", file, line, authorizer, ctx, got, !want) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | func testNothingPermitted(t *testing.T, authorizer security.Authorizer) { |
| 66 | _, file, line, _ := runtime.Caller(1) |
| 67 | var ( |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 68 | pserver, server = newPrincipal("server") |
| 69 | palice, alice = newPrincipal("alice") |
| 70 | pbob, bob = newPrincipal("random") |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 71 | |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 72 | serverAlice = bless(pserver, palice, server, "alice") |
| 73 | serverAliceFriend = bless(palice, pbob, serverAlice, "friend") |
| 74 | serverBob = bless(pserver, pbob, server, "bob") |
| 75 | |
| 76 | users = []security.Blessings{ |
| 77 | // blessings not recognized by "server" (since they are rooted at public |
| 78 | // keys not recognized as roots by pserver) |
| 79 | alice, |
| 80 | bob, |
| 81 | // blessings recognized by "server" (since they are its delegates) |
| 82 | serverAlice, |
| 83 | serverAliceFriend, |
| 84 | serverBob, |
| 85 | } |
| 86 | |
| 87 | invalidLabel = security.Label(3) |
| 88 | ) |
| 89 | // No principal (other than the server itself - self-RPCs are allowed) should have access to any |
| 90 | // valid or invalid label. |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 91 | for _, u := range users { |
| 92 | for _, l := range security.ValidLabels { |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 93 | ctx := security.NewContext(&security.ContextParams{ |
| 94 | LocalPrincipal: pserver, |
| 95 | LocalBlessings: server, |
| 96 | RemoteBlessings: u, |
| 97 | MethodTags: []interface{}{l}, |
| 98 | }) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 99 | if got := authorizer.Authorize(ctx); got == nil { |
| 100 | t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx) |
| 101 | } |
| 102 | } |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 103 | |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 104 | ctx := security.NewContext(&security.ContextParams{ |
| 105 | LocalPrincipal: pserver, |
| 106 | LocalBlessings: server, |
| 107 | RemoteBlessings: u, |
| 108 | MethodTags: []interface{}{invalidLabel}, |
| 109 | }) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 110 | if got := authorizer.Authorize(ctx); got == nil { |
| 111 | t.Errorf("%s:%d: %+v.Authorize(%v) returns nil, want error", file, line, authorizer, ctx) |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | func TestACLAuthorizer(t *testing.T) { |
| 117 | const ( |
| 118 | // Shorthands |
| 119 | R = security.ReadLabel |
| 120 | W = security.WriteLabel |
| 121 | A = security.AdminLabel |
| 122 | D = security.DebugLabel |
| 123 | M = security.MonitoringLabel |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 124 | X = security.ResolveLabel |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 125 | ) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 126 | type Expectations map[security.Blessings]security.LabelSet |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 127 | // Principals to test |
| 128 | var ( |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 129 | // Principals |
| 130 | pserver, server = newPrincipal("server") |
| 131 | palice, alice = newPrincipal("alice") |
| 132 | pbob, bob = newPrincipal("bob") |
| 133 | pche, che = newPrincipal("che") |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 134 | |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 135 | // Blessings from the server |
| 136 | serverAlice = bless(pserver, palice, server, "alice") |
| 137 | serverBob = bless(pserver, pbob, server, "bob") |
| 138 | serverChe = bless(pserver, pche, server, "che") |
| 139 | serverAliceFriend = bless(palice, pbob, serverAlice, "friend") |
| 140 | serverCheFriend = bless(pche, pbob, serverChe, "friend") |
| 141 | |
| 142 | authorizer security.Authorizer // the authorizer to test. |
| 143 | |
| 144 | runTests = func(expectations Expectations) { |
| 145 | _, file, line, _ := runtime.Caller(1) |
| 146 | for user, labels := range expectations { |
| 147 | for _, l := range security.ValidLabels { |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 148 | ctx := security.NewContext(&security.ContextParams{ |
| 149 | LocalPrincipal: pserver, |
| 150 | LocalBlessings: server, |
| 151 | RemoteBlessings: user, |
| 152 | MethodTags: []interface{}{l}, |
| 153 | }) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 154 | if got, want := authorizer.Authorize(ctx), labels.HasLabel(l); (got == nil) != want { |
Asim Shankar | 2519cc1 | 2014-11-10 21:16:53 -0800 | [diff] [blame] | 155 | t.Errorf("%s:%d: %+v.Authorize(%v) returned error: %v, want error: %v", file, line, authorizer, ctx, got, !want) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 156 | } |
| 157 | } |
| 158 | } |
| 159 | } |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 160 | ) |
| 161 | // Convenience function for combining Labels into a LabelSet. |
| 162 | LS := func(labels ...security.Label) security.LabelSet { |
| 163 | var ret security.LabelSet |
| 164 | for _, l := range labels { |
| 165 | ret = ret | security.LabelSet(l) |
| 166 | } |
| 167 | return ret |
| 168 | } |
| 169 | |
| 170 | // ACL for testing |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 171 | acl := security.ACL{ |
| 172 | In: map[security.BlessingPattern]security.LabelSet{ |
| 173 | "...": LS(R), |
| 174 | "server/alice/...": LS(W, R), |
| 175 | "server/alice": LS(A, D, M), |
| 176 | "server/bob": LS(D, M), |
| 177 | "server/che/...": LS(W, R), |
| 178 | "server/che": LS(W, R), |
| 179 | }, |
| 180 | NotIn: map[string]security.LabelSet{ |
| 181 | "server/che/friend": LS(W), |
| 182 | }, |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | // Authorizations for the above ACL. |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 186 | expectations := Expectations{ |
| 187 | alice: LS(R), // "..." ACL entry. |
| 188 | bob: LS(R), // "..." ACL entry. |
| 189 | che: LS(R), // "..." ACL entry. |
| 190 | server: security.AllLabels, // self RPC |
| 191 | serverAlice: LS(R, W, A, D, M), // "server/alice/..." ACL entry |
| 192 | serverBob: LS(R, D, M), // "..." and "server/bob" ACL entries |
| 193 | serverAliceFriend: LS(W, R), // "server/alice/..." ACL entry. |
| 194 | serverChe: LS(W, R), // "server/che" ACL entry. |
| 195 | serverCheFriend: LS(R), // "server/che/..." ACL entry, with the "server/che/friend" NotIn exception. |
| 196 | nil: LS(R), // No blessings presented, same authorizations as "..." ACL entry. |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 197 | } |
| 198 | // Create an aclAuthorizer based on the ACL and verify the authorizations. |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 199 | authorizer = NewACLAuthorizer(acl) |
| 200 | runTests(expectations) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 201 | testSelfRPCs(t, authorizer) |
| 202 | |
| 203 | // Create a fileACLAuthorizer by saving the ACL in a file, and verify the |
| 204 | // authorizations. |
| 205 | fileName := saveACLToTempFile(acl) |
| 206 | defer os.Remove(fileName) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 207 | authorizer = NewFileACLAuthorizer(fileName) |
| 208 | runTests(expectations) |
| 209 | testSelfRPCs(t, authorizer) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 210 | |
| 211 | // Modify the ACL stored in the file and verify that the authorizations appropriately |
| 212 | // change for the fileACLAuthorizer. |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 213 | acl.In["server/bob"] = LS(R, W, A, D, M) |
| 214 | expectations[serverBob] = LS(R, W, A, D, M) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 215 | updateACLInFile(fileName, acl) |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 216 | runTests(expectations) |
| 217 | testSelfRPCs(t, authorizer) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 218 | |
| 219 | // Update the ACL file with invalid contents and verify that no requests are |
| 220 | // authorized. |
| 221 | f, err := os.OpenFile(fileName, os.O_WRONLY, 0600) |
| 222 | if err != nil { |
| 223 | panic(err) |
| 224 | } |
| 225 | f.Write([]byte("invalid ACL")) |
| 226 | f.Close() |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 227 | testNothingPermitted(t, authorizer) |
| 228 | } |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 229 | |
Asim Shankar | bf6263f | 2014-10-01 12:32:30 -0700 | [diff] [blame] | 230 | func TestFileACLAuthorizerOnNonExistentFile(t *testing.T) { |
| 231 | testNothingPermitted(t, NewFileACLAuthorizer("fileDoesNotExist")) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | func TestNilACLAuthorizer(t *testing.T) { |
Tilak Sharma | b88a111 | 2014-08-15 17:17:12 -0700 | [diff] [blame] | 235 | authorizer := NewACLAuthorizer(nullACL) |
Tilak Sharma | 3ed3024 | 2014-08-11 11:45:55 -0700 | [diff] [blame] | 236 | testNothingPermitted(t, authorizer) |
| 237 | testSelfRPCs(t, authorizer) |
| 238 | } |