func GetEffectivePolicyRules(ctx kapi.Context, ruleResolver rulevalidation.AuthorizationRuleResolver, clusterPolicyGetter client.ClusterPolicyLister) ([]authorizationapi.PolicyRule, []error) { namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, []error{kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace))} } user, exists := kapi.UserFrom(ctx) if !exists { return nil, []error{kapierrors.NewBadRequest(fmt.Sprintf("user missing from context"))} } var errors []error var rules []authorizationapi.PolicyRule namespaceRules, err := ruleResolver.RulesFor(user, namespace) if err != nil { errors = append(errors, err) } for _, rule := range namespaceRules { rules = append(rules, rulevalidation.BreakdownRule(rule)...) } if scopes := user.GetExtra()[authorizationapi.ScopesKey]; len(scopes) > 0 { rules, err = filterRulesByScopes(rules, scopes, namespace, clusterPolicyGetter) if err != nil { return nil, []error{kapierrors.NewInternalError(err)} } } if compactedRules, err := rulevalidation.CompactRules(rules); err == nil { rules = compactedRules } sort.Sort(authorizationapi.SortableRuleSlice(rules)) return rules, errors }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { rulesReview, ok := obj.(*authorizationapi.SelfSubjectRulesReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectRulesReview: %#v", obj)) } namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace)) } user, exists := kapi.UserFrom(ctx) if !exists { return nil, kapierrors.NewBadRequest(fmt.Sprintf("user missing from context")) } errors := []error{} rules := []authorizationapi.PolicyRule{} namespaceRules, err := r.ruleResolver.GetEffectivePolicyRules(ctx) if err != nil { errors = append(errors, err) } for _, rule := range namespaceRules { rules = append(rules, rulevalidation.BreakdownRule(rule)...) } if len(namespace) != 0 { masterContext := kapi.WithNamespace(ctx, kapi.NamespaceNone) clusterRules, err := r.ruleResolver.GetEffectivePolicyRules(masterContext) if err != nil { errors = append(errors, err) } for _, rule := range clusterRules { rules = append(rules, rulevalidation.BreakdownRule(rule)...) } } switch { case rulesReview.Spec.Scopes == nil: if scopes, _ := user.GetExtra()[authorizationapi.ScopesKey]; len(scopes) > 0 { rules, err = r.filterRulesByScopes(rules, scopes, namespace) if err != nil { return nil, kapierrors.NewInternalError(err) } } case len(rulesReview.Spec.Scopes) > 0: rules, err = r.filterRulesByScopes(rules, rulesReview.Spec.Scopes, namespace) if err != nil { return nil, kapierrors.NewInternalError(err) } } if compactedRules, err := rulevalidation.CompactRules(rules); err == nil { rules = compactedRules } sort.Sort(authorizationapi.SortableRuleSlice(rules)) ret := &authorizationapi.SelfSubjectRulesReview{ Status: authorizationapi.SubjectRulesReviewStatus{ Rules: rules, }, } if len(errors) != 0 { ret.Status.EvaluationError = kutilerrors.NewAggregate(errors).Error() } return ret, nil }
func TestCompactRules(t *testing.T) { testcases := map[string]struct { Rules []api.PolicyRule Expected []api.PolicyRule }{ "empty": { Rules: []api.PolicyRule{}, Expected: []api.PolicyRule{}, }, "simple": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("update", "patch"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("create"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("delete"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("educate"), APIGroups: []string{""}, Resources: sets.NewString("dolphins")}, // nil verbs are preserved in non-merge cases. // these are the pirates who don't do anything. {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pirates")}, // Test merging into a nil Verbs string set {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pods")}, {Verbs: sets.NewString("create"), APIGroups: []string{""}, Resources: sets.NewString("pods")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("create", "delete"), APIGroups: []string{"extensions"}, Resources: sets.NewString("daemonsets")}, {Verbs: sets.NewString("get", "list", "update", "patch"), APIGroups: []string{""}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("educate"), APIGroups: []string{""}, Resources: sets.NewString("dolphins")}, {Verbs: nil, APIGroups: []string{""}, Resources: sets.NewString("pirates")}, {Verbs: sets.NewString("create"), APIGroups: []string{""}, Resources: sets.NewString("pods")}, }, }, "complex multi-group": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, {Verbs: sets.NewString("list"), APIGroups: []string{"", "builds.openshift.io"}, Resources: sets.NewString("builds")}, }, }, "complex multi-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds", "images")}, }, }, "complex named-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild2")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild")}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), ResourceNames: sets.NewString("mybuild2")}, }, }, "complex non-resource": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/")}, {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/foo")}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/")}, {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), NonResourceURLs: sets.NewString("/foo")}, }, }, "complex attributes": { Rules: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, }, Expected: []api.PolicyRule{ {Verbs: sets.NewString("get"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, {Verbs: sets.NewString("list"), APIGroups: []string{""}, Resources: sets.NewString("builds"), AttributeRestrictions: &api.IsPersonalSubjectAccessReview{}}, }, }, } for k, tc := range testcases { rules := tc.Rules originalRules, err := kapi.Scheme.DeepCopy(tc.Rules) if err != nil { t.Errorf("%s: couldn't copy rules: %v", k, err) continue } compacted, err := CompactRules(tc.Rules) if err != nil { t.Errorf("%s: unexpected error: %v", k, err) continue } if !reflect.DeepEqual(rules, originalRules) { t.Errorf("%s: CompactRules mutated rules. Expected\n%#v\ngot\n%#v", k, originalRules, rules) continue } if covers, missing := Covers(compacted, rules); !covers { t.Errorf("%s: compacted rules did not cover original rules. missing: %#v", k, missing) continue } if covers, missing := Covers(rules, compacted); !covers { t.Errorf("%s: original rules did not cover compacted rules. missing: %#v", k, missing) continue } sort.Stable(api.SortableRuleSlice(compacted)) sort.Stable(api.SortableRuleSlice(tc.Expected)) if !reflect.DeepEqual(compacted, tc.Expected) { t.Errorf("%s: Expected\n%#v\ngot\n%#v", k, tc.Expected, compacted) continue } } }