k8s.io/apiserver@v0.31.1/pkg/authorization/union/union_test.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package union
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"k8s.io/apiserver/pkg/authentication/user"
    27  	"k8s.io/apiserver/pkg/authorization/authorizer"
    28  )
    29  
    30  type mockAuthzHandler struct {
    31  	decision authorizer.Decision
    32  	err      error
    33  }
    34  
    35  func (mock *mockAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
    36  	return mock.decision, "", mock.err
    37  }
    38  
    39  func TestAuthorizationSecondPasses(t *testing.T) {
    40  	handler1 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}
    41  	handler2 := &mockAuthzHandler{decision: authorizer.DecisionAllow}
    42  	authzHandler := New(handler1, handler2)
    43  
    44  	authorized, _, _ := authzHandler.Authorize(context.Background(), nil)
    45  	if authorized != authorizer.DecisionAllow {
    46  		t.Errorf("Unexpected authorization failure")
    47  	}
    48  }
    49  
    50  func TestAuthorizationFirstPasses(t *testing.T) {
    51  	handler1 := &mockAuthzHandler{decision: authorizer.DecisionAllow}
    52  	handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}
    53  	authzHandler := New(handler1, handler2)
    54  
    55  	authorized, _, _ := authzHandler.Authorize(context.Background(), nil)
    56  	if authorized != authorizer.DecisionAllow {
    57  		t.Errorf("Unexpected authorization failure")
    58  	}
    59  }
    60  
    61  func TestAuthorizationNonePasses(t *testing.T) {
    62  	handler1 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}
    63  	handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}
    64  	authzHandler := New(handler1, handler2)
    65  
    66  	authorized, _, _ := authzHandler.Authorize(context.Background(), nil)
    67  	if authorized == authorizer.DecisionAllow {
    68  		t.Errorf("Expected failed authorization")
    69  	}
    70  }
    71  
    72  func TestAuthorizationError(t *testing.T) {
    73  	handler1 := &mockAuthzHandler{err: fmt.Errorf("foo")}
    74  	handler2 := &mockAuthzHandler{err: fmt.Errorf("foo")}
    75  	authzHandler := New(handler1, handler2)
    76  
    77  	_, _, err := authzHandler.Authorize(context.Background(), nil)
    78  	if err == nil {
    79  		t.Errorf("Expected error: %v", err)
    80  	}
    81  }
    82  
    83  type mockAuthzRuleHandler struct {
    84  	resourceRules    []authorizer.ResourceRuleInfo
    85  	nonResourceRules []authorizer.NonResourceRuleInfo
    86  	err              error
    87  }
    88  
    89  func (mock *mockAuthzRuleHandler) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
    90  	if mock.err != nil {
    91  		return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, mock.err
    92  	}
    93  	return mock.resourceRules, mock.nonResourceRules, false, nil
    94  }
    95  
    96  func TestAuthorizationResourceRules(t *testing.T) {
    97  	handler1 := &mockAuthzRuleHandler{
    98  		resourceRules: []authorizer.ResourceRuleInfo{
    99  			&authorizer.DefaultResourceRuleInfo{
   100  				Verbs:     []string{"*"},
   101  				APIGroups: []string{"*"},
   102  				Resources: []string{"bindings"},
   103  			},
   104  			&authorizer.DefaultResourceRuleInfo{
   105  				Verbs:     []string{"get", "list", "watch"},
   106  				APIGroups: []string{"*"},
   107  				Resources: []string{"*"},
   108  			},
   109  		},
   110  	}
   111  	handler2 := &mockAuthzRuleHandler{
   112  		resourceRules: []authorizer.ResourceRuleInfo{
   113  			&authorizer.DefaultResourceRuleInfo{
   114  				Verbs:     []string{"*"},
   115  				APIGroups: []string{"*"},
   116  				Resources: []string{"events"},
   117  			},
   118  			&authorizer.DefaultResourceRuleInfo{
   119  				Verbs:         []string{"get"},
   120  				APIGroups:     []string{"*"},
   121  				Resources:     []string{"*"},
   122  				ResourceNames: []string{"foo"},
   123  			},
   124  		},
   125  	}
   126  
   127  	expected := []authorizer.DefaultResourceRuleInfo{
   128  		{
   129  			Verbs:     []string{"*"},
   130  			APIGroups: []string{"*"},
   131  			Resources: []string{"bindings"},
   132  		},
   133  		{
   134  			Verbs:     []string{"get", "list", "watch"},
   135  			APIGroups: []string{"*"},
   136  			Resources: []string{"*"},
   137  		},
   138  		{
   139  			Verbs:     []string{"*"},
   140  			APIGroups: []string{"*"},
   141  			Resources: []string{"events"},
   142  		},
   143  		{
   144  			Verbs:         []string{"get"},
   145  			APIGroups:     []string{"*"},
   146  			Resources:     []string{"*"},
   147  			ResourceNames: []string{"foo"},
   148  		},
   149  	}
   150  
   151  	authzRulesHandler := NewRuleResolvers(handler1, handler2)
   152  
   153  	rules, _, _, _ := authzRulesHandler.RulesFor(nil, "")
   154  	actual := getResourceRules(rules)
   155  	if !reflect.DeepEqual(expected, actual) {
   156  		t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual)
   157  	}
   158  }
   159  
   160  func TestAuthorizationNonResourceRules(t *testing.T) {
   161  	handler1 := &mockAuthzRuleHandler{
   162  		nonResourceRules: []authorizer.NonResourceRuleInfo{
   163  			&authorizer.DefaultNonResourceRuleInfo{
   164  				Verbs:           []string{"get"},
   165  				NonResourceURLs: []string{"/api"},
   166  			},
   167  		},
   168  	}
   169  
   170  	handler2 := &mockAuthzRuleHandler{
   171  		nonResourceRules: []authorizer.NonResourceRuleInfo{
   172  			&authorizer.DefaultNonResourceRuleInfo{
   173  				Verbs:           []string{"get"},
   174  				NonResourceURLs: []string{"/api/*"},
   175  			},
   176  		},
   177  	}
   178  
   179  	expected := []authorizer.DefaultNonResourceRuleInfo{
   180  		{
   181  			Verbs:           []string{"get"},
   182  			NonResourceURLs: []string{"/api"},
   183  		},
   184  		{
   185  			Verbs:           []string{"get"},
   186  			NonResourceURLs: []string{"/api/*"},
   187  		},
   188  	}
   189  
   190  	authzRulesHandler := NewRuleResolvers(handler1, handler2)
   191  
   192  	_, rules, _, _ := authzRulesHandler.RulesFor(nil, "")
   193  	actual := getNonResourceRules(rules)
   194  	if !reflect.DeepEqual(expected, actual) {
   195  		t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual)
   196  	}
   197  }
   198  
   199  func getResourceRules(infos []authorizer.ResourceRuleInfo) []authorizer.DefaultResourceRuleInfo {
   200  	rules := make([]authorizer.DefaultResourceRuleInfo, len(infos))
   201  	for i, info := range infos {
   202  		rules[i] = authorizer.DefaultResourceRuleInfo{
   203  			Verbs:         info.GetVerbs(),
   204  			APIGroups:     info.GetAPIGroups(),
   205  			Resources:     info.GetResources(),
   206  			ResourceNames: info.GetResourceNames(),
   207  		}
   208  	}
   209  	return rules
   210  }
   211  
   212  func getNonResourceRules(infos []authorizer.NonResourceRuleInfo) []authorizer.DefaultNonResourceRuleInfo {
   213  	rules := make([]authorizer.DefaultNonResourceRuleInfo, len(infos))
   214  	for i, info := range infos {
   215  		rules[i] = authorizer.DefaultNonResourceRuleInfo{
   216  			Verbs:           info.GetVerbs(),
   217  			NonResourceURLs: info.GetNonResourceURLs(),
   218  		}
   219  	}
   220  	return rules
   221  }
   222  
   223  func TestAuthorizationUnequivocalDeny(t *testing.T) {
   224  	cs := []struct {
   225  		authorizers []authorizer.Authorizer
   226  		decision    authorizer.Decision
   227  	}{
   228  		{
   229  			authorizers: []authorizer.Authorizer{},
   230  			decision:    authorizer.DecisionNoOpinion,
   231  		},
   232  		{
   233  			authorizers: []authorizer.Authorizer{
   234  				&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
   235  				&mockAuthzHandler{decision: authorizer.DecisionAllow},
   236  				&mockAuthzHandler{decision: authorizer.DecisionDeny},
   237  			},
   238  			decision: authorizer.DecisionAllow,
   239  		},
   240  		{
   241  			authorizers: []authorizer.Authorizer{
   242  				&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
   243  				&mockAuthzHandler{decision: authorizer.DecisionDeny},
   244  				&mockAuthzHandler{decision: authorizer.DecisionAllow},
   245  			},
   246  			decision: authorizer.DecisionDeny,
   247  		},
   248  		{
   249  			authorizers: []authorizer.Authorizer{
   250  				&mockAuthzHandler{decision: authorizer.DecisionNoOpinion},
   251  				&mockAuthzHandler{decision: authorizer.DecisionDeny, err: errors.New("webhook failed closed")},
   252  				&mockAuthzHandler{decision: authorizer.DecisionAllow},
   253  			},
   254  			decision: authorizer.DecisionDeny,
   255  		},
   256  	}
   257  	for i, c := range cs {
   258  		t.Run(fmt.Sprintf("case %v", i), func(t *testing.T) {
   259  			authzHandler := New(c.authorizers...)
   260  
   261  			decision, _, _ := authzHandler.Authorize(context.Background(), nil)
   262  			if decision != c.decision {
   263  				t.Errorf("Unexpected authorization failure: %v, expected: %v", decision, c.decision)
   264  			}
   265  		})
   266  	}
   267  }