go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/tokenserver/appengine/impl/delegation/config_validation_test.go (about)

     1  // Copyright 2016 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 delegation
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  
    21  	"google.golang.org/protobuf/encoding/prototext"
    22  
    23  	"go.chromium.org/luci/config/validation"
    24  
    25  	"go.chromium.org/luci/tokenserver/api/admin/v1"
    26  	"go.chromium.org/luci/tokenserver/appengine/impl/utils/policy"
    27  
    28  	. "github.com/smartystreets/goconvey/convey"
    29  	. "go.chromium.org/luci/common/testing/assertions"
    30  )
    31  
    32  func TestValidation(t *testing.T) {
    33  	t.Parallel()
    34  
    35  	cases := []struct {
    36  		Cfg    string
    37  		Errors []string
    38  	}{
    39  		{
    40  			// No errors, "normal looking" config.
    41  			Cfg: `
    42  				rules {
    43  					name: "rule 1"
    44  					requestor: "user:some-app@appspot.gserviceaccount.com"
    45  					target_service: "service:some-service"
    46  					allowed_to_impersonate: "group:some-group"
    47  					allowed_audience: "REQUESTOR"
    48  					max_validity_duration: 86400
    49  				}
    50  
    51  				rules {
    52  					name: "rule 2"
    53  					requestor: "group:some-group"
    54  					target_service: "*"
    55  					allowed_to_impersonate: "group:another-group"
    56  					allowed_audience: "*"
    57  					max_validity_duration: 86400
    58  				}
    59  			`,
    60  		},
    61  
    62  		{
    63  			// Duplicate names.
    64  			Cfg: `
    65  				rules {
    66  					name: "rule 1"
    67  					requestor: "user:some-app@appspot.gserviceaccount.com"
    68  					target_service: "service:some-service"
    69  					allowed_to_impersonate: "group:some-group"
    70  					allowed_audience: "REQUESTOR"
    71  					max_validity_duration: 86400
    72  				}
    73  
    74  				rules {
    75  					name: "rule 1"
    76  					requestor: "group:some-group"
    77  					target_service: "*"
    78  					allowed_to_impersonate: "group:another-group"
    79  					allowed_audience: "*"
    80  					max_validity_duration: 86400
    81  				}
    82  			`,
    83  			Errors: []string{`two rules with identical name "rule 1"`},
    84  		},
    85  
    86  		{
    87  			// Missing required fields.
    88  			Cfg: `
    89  				rules {
    90  				}
    91  			`,
    92  			Errors: []string{
    93  				`"name" is required`,
    94  				`"requestor" is required`,
    95  				`"allowed_to_impersonate" is required`,
    96  				`"allowed_audience" is required`,
    97  				`"target_service" is required`,
    98  				`"max_validity_duration" is required`,
    99  			},
   100  		},
   101  
   102  		{
   103  			// Validity duration out of range.
   104  			Cfg: `
   105  				rules {
   106  					name: "rule 1"
   107  					requestor: "user:some-app@appspot.gserviceaccount.com"
   108  					target_service: "service:some-service"
   109  					allowed_to_impersonate: "group:some-group"
   110  					allowed_audience: "REQUESTOR"
   111  					max_validity_duration: -1
   112  				}
   113  				rules {
   114  					name: "rule 2"
   115  					requestor: "user:some-app@appspot.gserviceaccount.com"
   116  					target_service: "service:some-service"
   117  					allowed_to_impersonate: "group:some-group"
   118  					allowed_audience: "REQUESTOR"
   119  					max_validity_duration: 86401
   120  				}
   121  			`,
   122  			Errors: []string{
   123  				`in "delegation.cfg" (rule #1: "rule 1"): "max_validity_duration" must be positive`,
   124  				`in "delegation.cfg" (rule #2: "rule 2"): "max_validity_duration" must be smaller than 86401`,
   125  			},
   126  		},
   127  
   128  		{
   129  			// Bad requestor.
   130  			Cfg: `
   131  				rules {
   132  					name: "rule 1"
   133  					requestor: "user:some-app@appspot.gserviceaccount.com" # ok
   134  					requestor: "service:blah" # ok
   135  					requestor: "group:some-group" # ok
   136  					requestor: "*" # not ok
   137  					requestor: "some junk" # not ok
   138  					requestor: "group:" # not ok
   139  					target_service: "service:some-service"
   140  					allowed_to_impersonate: "group:some-group"
   141  					allowed_audience: "REQUESTOR"
   142  					max_validity_duration: 3600
   143  				}
   144  			`,
   145  			Errors: []string{
   146  				`in "delegation.cfg" (rule #1: "rule 1" / "requestor"): auth: bad identity string "*"`,
   147  				`in "delegation.cfg" (rule #1: "rule 1" / "requestor"): auth: bad identity string "some junk"`,
   148  				`in "delegation.cfg" (rule #1: "rule 1" / "requestor"): bad group entry "group:"`,
   149  			},
   150  		},
   151  
   152  		{
   153  			// Bad allowed_to_impersonate.
   154  			Cfg: `
   155  				rules {
   156  					name: "rule 1"
   157  					requestor: "user:some-app@appspot.gserviceaccount.com"
   158  					target_service: "service:some-service"
   159  					allowed_to_impersonate: "user:abc@example.com" # ok
   160  					allowed_to_impersonate: "group:some-group" # ok
   161  					allowed_to_impersonate: "REQUESTOR" # ok
   162  					allowed_to_impersonate: "*" # not OK
   163  					allowed_audience: "REQUESTOR"
   164  					max_validity_duration: 86400
   165  				}
   166  			`,
   167  			Errors: []string{
   168  				`in "delegation.cfg" (rule #1: "rule 1" / "allowed_to_impersonate"): auth: bad identity string "*"`,
   169  			},
   170  		},
   171  
   172  		{
   173  			// Bad allowed_audience.
   174  			Cfg: `
   175  				rules {
   176  					name: "rule 1"
   177  					requestor: "user:some-app@appspot.gserviceaccount.com"
   178  					target_service: "service:some-service"
   179  					allowed_to_impersonate: "user:abc@example.com"
   180  					allowed_audience: "REQUESTOR" # ok
   181  					allowed_audience: "*" # ok
   182  					allowed_audience: "user:abc@example.com" # ok
   183  					allowed_audience: "group:abc" # ok
   184  					allowed_audience: "some junk" # not ok
   185  					max_validity_duration: 86400
   186  				}
   187  			`,
   188  			Errors: []string{
   189  				`in "delegation.cfg" (rule #1: "rule 1" / "allowed_audience"): auth: bad identity string "some junk"`,
   190  			},
   191  		},
   192  
   193  		{
   194  			// Bad target_service.
   195  			Cfg: `
   196  				rules {
   197  					name: "rule 1"
   198  					requestor: "user:some-app@appspot.gserviceaccount.com"
   199  					target_service: "service:some-service" # ok
   200  					target_service: "user:abc@example.com" # not ok
   201  					target_service: "group:some-group" # not ok
   202  					allowed_to_impersonate: "user:abc@example.com"
   203  					allowed_audience: "REQUESTOR"
   204  					max_validity_duration: 86400
   205  				}
   206  			`,
   207  			Errors: []string{
   208  				`in "delegation.cfg" (rule #1: "rule 1" / "target_service"): identity of kind "user" is not allowed here`,
   209  				`in "delegation.cfg" (rule #1: "rule 1" / "target_service"): group entries are not allowed`,
   210  			},
   211  		},
   212  	}
   213  
   214  	Convey("Validation works", t, func(c C) {
   215  		for idx, cs := range cases {
   216  			c.Printf("Case #%d\n", idx)
   217  
   218  			cfg := &admin.DelegationPermissions{}
   219  			err := prototext.Unmarshal([]byte(cs.Cfg), cfg)
   220  			So(err, ShouldBeNil)
   221  
   222  			ctx := &validation.Context{Context: context.Background()}
   223  			validateConfigBundle(ctx, policy.ConfigBundle{delegationCfg: cfg})
   224  			verr := ctx.Finalize()
   225  
   226  			if len(cs.Errors) == 0 { // no errors expected
   227  				So(verr, ShouldBeNil)
   228  			} else {
   229  				verr := verr.(*validation.Error)
   230  				So(len(verr.Errors), ShouldEqual, len(cs.Errors))
   231  				for i, err := range verr.Errors {
   232  					So(err, ShouldErrLike, cs.Errors[i])
   233  				}
   234  			}
   235  		}
   236  	})
   237  }