1// +build linux windows 2 3/* 4 * 5 * Copyright 2018 gRPC authors. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 */ 20 21package alts 22 23import ( 24 "context" 25 "io" 26 "os" 27 "strings" 28 "testing" 29 30 "google.golang.org/grpc/codes" 31 altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp" 32 "google.golang.org/grpc/peer" 33 "google.golang.org/grpc/status" 34) 35 36const ( 37 testServiceAccount1 = "service_account1" 38 testServiceAccount2 = "service_account2" 39 testServiceAccount3 = "service_account3" 40) 41 42func setupManufacturerReader(testOS string, reader func() (io.Reader, error)) func() { 43 tmpOS := runningOS 44 tmpReader := manufacturerReader 45 46 // Set test OS and reader function. 47 runningOS = testOS 48 manufacturerReader = reader 49 return func() { 50 runningOS = tmpOS 51 manufacturerReader = tmpReader 52 } 53 54} 55 56func setup(testOS string, testReader io.Reader) func() { 57 reader := func() (io.Reader, error) { 58 return testReader, nil 59 } 60 return setupManufacturerReader(testOS, reader) 61} 62 63func setupError(testOS string, err error) func() { 64 reader := func() (io.Reader, error) { 65 return nil, err 66 } 67 return setupManufacturerReader(testOS, reader) 68} 69 70func (s) TestIsRunningOnGCP(t *testing.T) { 71 for _, tc := range []struct { 72 description string 73 testOS string 74 testReader io.Reader 75 out bool 76 }{ 77 // Linux tests. 78 {"linux: not a GCP platform", "linux", strings.NewReader("not GCP"), false}, 79 {"Linux: GCP platform (Google)", "linux", strings.NewReader("Google"), true}, 80 {"Linux: GCP platform (Google Compute Engine)", "linux", strings.NewReader("Google Compute Engine"), true}, 81 {"Linux: GCP platform (Google Compute Engine) with extra spaces", "linux", strings.NewReader(" Google Compute Engine "), true}, 82 // Windows tests. 83 {"windows: not a GCP platform", "windows", strings.NewReader("not GCP"), false}, 84 {"windows: GCP platform (Google)", "windows", strings.NewReader("Google"), true}, 85 {"windows: GCP platform (Google) with extra spaces", "windows", strings.NewReader(" Google "), true}, 86 } { 87 reverseFunc := setup(tc.testOS, tc.testReader) 88 if got, want := isRunningOnGCP(), tc.out; got != want { 89 t.Errorf("%v: isRunningOnGCP()=%v, want %v", tc.description, got, want) 90 } 91 reverseFunc() 92 } 93} 94 95func (s) TestIsRunningOnGCPNoProductNameFile(t *testing.T) { 96 reverseFunc := setupError("linux", os.ErrNotExist) 97 if isRunningOnGCP() { 98 t.Errorf("ErrNotExist: isRunningOnGCP()=true, want false") 99 } 100 reverseFunc() 101} 102 103func (s) TestAuthInfoFromContext(t *testing.T) { 104 ctx := context.Background() 105 altsAuthInfo := &fakeALTSAuthInfo{} 106 p := &peer.Peer{ 107 AuthInfo: altsAuthInfo, 108 } 109 for _, tc := range []struct { 110 desc string 111 ctx context.Context 112 success bool 113 out AuthInfo 114 }{ 115 { 116 "working case", 117 peer.NewContext(ctx, p), 118 true, 119 altsAuthInfo, 120 }, 121 } { 122 authInfo, err := AuthInfoFromContext(tc.ctx) 123 if got, want := (err == nil), tc.success; got != want { 124 t.Errorf("%v: AuthInfoFromContext(_)=(err=nil)=%v, want %v", tc.desc, got, want) 125 } 126 if got, want := authInfo, tc.out; got != want { 127 t.Errorf("%v:, AuthInfoFromContext(_)=(%v, _), want (%v, _)", tc.desc, got, want) 128 } 129 } 130} 131 132func (s) TestAuthInfoFromPeer(t *testing.T) { 133 altsAuthInfo := &fakeALTSAuthInfo{} 134 p := &peer.Peer{ 135 AuthInfo: altsAuthInfo, 136 } 137 for _, tc := range []struct { 138 desc string 139 p *peer.Peer 140 success bool 141 out AuthInfo 142 }{ 143 { 144 "working case", 145 p, 146 true, 147 altsAuthInfo, 148 }, 149 } { 150 authInfo, err := AuthInfoFromPeer(tc.p) 151 if got, want := (err == nil), tc.success; got != want { 152 t.Errorf("%v: AuthInfoFromPeer(_)=(err=nil)=%v, want %v", tc.desc, got, want) 153 } 154 if got, want := authInfo, tc.out; got != want { 155 t.Errorf("%v:, AuthInfoFromPeer(_)=(%v, _), want (%v, _)", tc.desc, got, want) 156 } 157 } 158} 159 160func (s) TestClientAuthorizationCheck(t *testing.T) { 161 ctx := context.Background() 162 altsAuthInfo := &fakeALTSAuthInfo{testServiceAccount1} 163 p := &peer.Peer{ 164 AuthInfo: altsAuthInfo, 165 } 166 for _, tc := range []struct { 167 desc string 168 ctx context.Context 169 expectedServiceAccounts []string 170 success bool 171 code codes.Code 172 }{ 173 { 174 "working case", 175 peer.NewContext(ctx, p), 176 []string{testServiceAccount1, testServiceAccount2}, 177 true, 178 codes.OK, // err is nil, code is OK. 179 }, 180 { 181 "working case (case ignored)", 182 peer.NewContext(ctx, p), 183 []string{strings.ToUpper(testServiceAccount1), testServiceAccount2}, 184 true, 185 codes.OK, // err is nil, code is OK. 186 }, 187 { 188 "context does not have AuthInfo", 189 ctx, 190 []string{testServiceAccount1, testServiceAccount2}, 191 false, 192 codes.PermissionDenied, 193 }, 194 { 195 "unauthorized client", 196 peer.NewContext(ctx, p), 197 []string{testServiceAccount2, testServiceAccount3}, 198 false, 199 codes.PermissionDenied, 200 }, 201 } { 202 err := ClientAuthorizationCheck(tc.ctx, tc.expectedServiceAccounts) 203 if got, want := (err == nil), tc.success; got != want { 204 t.Errorf("%v: ClientAuthorizationCheck(_, %v)=(err=nil)=%v, want %v", tc.desc, tc.expectedServiceAccounts, got, want) 205 } 206 if got, want := status.Code(err), tc.code; got != want { 207 t.Errorf("%v: ClientAuthorizationCheck(_, %v).Code=%v, want %v", tc.desc, tc.expectedServiceAccounts, got, want) 208 } 209 } 210} 211 212type fakeALTSAuthInfo struct { 213 peerServiceAccount string 214} 215 216func (*fakeALTSAuthInfo) AuthType() string { return "" } 217func (*fakeALTSAuthInfo) ApplicationProtocol() string { return "" } 218func (*fakeALTSAuthInfo) RecordProtocol() string { return "" } 219func (*fakeALTSAuthInfo) SecurityLevel() altspb.SecurityLevel { 220 return altspb.SecurityLevel_SECURITY_NONE 221} 222func (f *fakeALTSAuthInfo) PeerServiceAccount() string { return f.peerServiceAccount } 223func (*fakeALTSAuthInfo) LocalServiceAccount() string { return "" } 224func (*fakeALTSAuthInfo) PeerRPCVersions() *altspb.RpcProtocolVersions { return nil } 225