| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 package serviceaccounts |
| 16 |
| 17 import ( |
| 18 "net" |
| 19 "testing" |
| 20 "time" |
| 21 |
| 22 "golang.org/x/net/context" |
| 23 |
| 24 "github.com/luci/gae/service/info" |
| 25 "github.com/luci/luci-go/appengine/gaetesting" |
| 26 "github.com/luci/luci-go/server/auth" |
| 27 "github.com/luci/luci-go/server/auth/authdb" |
| 28 "github.com/luci/luci-go/server/auth/authtest" |
| 29 "github.com/luci/luci-go/server/auth/signing" |
| 30 "github.com/luci/luci-go/server/auth/signing/signingtest" |
| 31 "github.com/luci/luci-go/tokenserver/api/minter/v1" |
| 32 |
| 33 "github.com/luci/luci-go/common/clock" |
| 34 "github.com/luci/luci-go/common/clock/testclock" |
| 35 "github.com/luci/luci-go/common/proto/google" |
| 36 |
| 37 . "github.com/luci/luci-go/common/testing/assertions" |
| 38 . "github.com/smartystreets/goconvey/convey" |
| 39 ) |
| 40 |
| 41 func testingContext() context.Context { |
| 42 ctx := gaetesting.TestingContext() |
| 43 ctx = info.GetTestable(ctx).SetRequestID("gae-request-id") |
| 44 ctx, _ = testclock.UseTime(ctx, time.Date(2015, time.February, 3, 4, 5,
6, 0, time.UTC)) |
| 45 return auth.WithState(ctx, &authtest.FakeState{ |
| 46 Identity: "user:requestor@example.com", |
| 47 PeerIPOverride: net.ParseIP("127.10.10.10"), |
| 48 FakeDB: &authdb.SnapshotDB{Rev: 1234}, |
| 49 }) |
| 50 } |
| 51 |
| 52 func testingSigner() signing.Signer { |
| 53 return signingtest.NewSigner(0, &signing.ServiceInfo{ |
| 54 ServiceAccountName: "signer@testing.host", |
| 55 AppID: "unit-tests", |
| 56 AppVersion: "mocked-ver", |
| 57 }) |
| 58 } |
| 59 |
| 60 func TestMintOAuthTokenGrant(t *testing.T) { |
| 61 t.Parallel() |
| 62 |
| 63 ctx := testingContext() |
| 64 |
| 65 Convey("with mocked config and state", t, func() { |
| 66 cfg, err := loadConfig(`rules { |
| 67 name: "rule 1" |
| 68 service_account: "account@robots.com" |
| 69 proxy: "user:requestor@example.com" |
| 70 end_user: "user:enduser@example.com" |
| 71 max_grant_validity_duration: 7200 |
| 72 }`) |
| 73 So(err, ShouldBeNil) |
| 74 |
| 75 var lastParams *mintParams |
| 76 mintMock := func(c context.Context, p *mintParams) (*minter.Mint
OAuthTokenGrantResponse, error) { |
| 77 lastParams = p |
| 78 expiry := clock.Now(c).Add(time.Duration(p.validityDurat
ion) * time.Second) |
| 79 return &minter.MintOAuthTokenGrantResponse{ |
| 80 GrantToken: "valid_token", |
| 81 Expiry: google.NewTimestamp(expiry), |
| 82 ServiceVersion: p.serviceVer, |
| 83 }, nil |
| 84 } |
| 85 |
| 86 rpc := MintOAuthTokenGrantRPC{ |
| 87 Signer: testingSigner(), |
| 88 Rules: func(context.Context) (*Rules, error) { return
cfg, nil }, |
| 89 mintMock: mintMock, |
| 90 } |
| 91 |
| 92 Convey("Happy path", func() { |
| 93 resp, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOA
uthTokenGrantRequest{ |
| 94 ServiceAccount: "account@robots.com", |
| 95 EndUser: "user:enduser@example.com", |
| 96 }) |
| 97 So(err, ShouldBeNil) |
| 98 So(resp.GrantToken, ShouldEqual, "valid_token") |
| 99 So(resp.ServiceVersion, ShouldEqual, "unit-tests/mocked-
ver") |
| 100 So(lastParams, ShouldResemble, &mintParams{ |
| 101 serviceAccount: "account@robots.com", |
| 102 proxyID: "user:requestor@example.com", |
| 103 endUserID: "user:enduser@example.com", |
| 104 validityDuration: 3600, // default |
| 105 serviceVer: "unit-tests/mocked-ver", |
| 106 }) |
| 107 }) |
| 108 |
| 109 Convey("Empty service account", func() { |
| 110 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 111 EndUser: "user:enduser@example.com", |
| 112 }) |
| 113 So(err, ShouldBeRPCInvalidArgument, "service_account is
required") |
| 114 }) |
| 115 |
| 116 Convey("Negative validity", func() { |
| 117 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 118 ServiceAccount: "account@robots.com", |
| 119 EndUser: "user:enduser@example.com", |
| 120 ValidityDuration: -1, |
| 121 }) |
| 122 So(err, ShouldBeRPCInvalidArgument, "validity_duration m
ust be positive") |
| 123 }) |
| 124 |
| 125 Convey("Empty end-user", func() { |
| 126 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 127 ServiceAccount: "account@robots.com", |
| 128 }) |
| 129 So(err, ShouldBeRPCInvalidArgument, "end_user is require
d") |
| 130 }) |
| 131 |
| 132 Convey("Bad end-user", func() { |
| 133 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 134 ServiceAccount: "account@robots.com", |
| 135 EndUser: "blah", |
| 136 }) |
| 137 So(err, ShouldBeRPCInvalidArgument, "bad identity string
") |
| 138 }) |
| 139 |
| 140 Convey("Unknown rule", func() { |
| 141 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 142 ServiceAccount: "unknown@robots.com", |
| 143 EndUser: "user:enduser@example.com", |
| 144 }) |
| 145 So(err, ShouldBeRPCPermissionDenied, "unknown service ac
count or not enough permissions to use it") |
| 146 }) |
| 147 |
| 148 Convey("Unauthorized caller", func() { |
| 149 ctx := auth.WithState(ctx, &authtest.FakeState{ |
| 150 Identity: "user:unknown@example.com", |
| 151 }) |
| 152 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 153 ServiceAccount: "account@robots.com", |
| 154 EndUser: "user:enduser@example.com", |
| 155 }) |
| 156 So(err, ShouldBeRPCPermissionDenied, "unknown service ac
count or not enough permissions to use it") |
| 157 }) |
| 158 |
| 159 Convey("Too high validity duration", func() { |
| 160 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 161 ServiceAccount: "account@robots.com", |
| 162 EndUser: "user:enduser@example.com", |
| 163 ValidityDuration: 7201, |
| 164 }) |
| 165 So(err, ShouldBeRPCInvalidArgument, `per rule "rule 1" t
he validity duration should be <= 7200`) |
| 166 }) |
| 167 |
| 168 Convey("Unauthorized end-user", func() { |
| 169 _, err := rpc.MintOAuthTokenGrant(ctx, &minter.MintOAuth
TokenGrantRequest{ |
| 170 ServiceAccount: "account@robots.com", |
| 171 EndUser: "user:unknown@example.com", |
| 172 }) |
| 173 So(err, ShouldBeRPCPermissionDenied, |
| 174 `per rule "rule 1" the user "user:unknown@exampl
e.com" is not authorized to use the service account "account@robots.com"`) |
| 175 }) |
| 176 }) |
| 177 } |
| OLD | NEW |