func (a DefaultAuthorizationAttributes) RuleMatches(rule authorizationapi.PolicyRule) (bool, error) {
	if a.IsNonResourceURL() {
		if a.nonResourceMatches(rule) {
			if a.verbMatches(rule.Verbs) {
				return true, nil
			}
		}

		return false, nil
	}

	if a.verbMatches(rule.Verbs) {
		allowedResourceTypes := authorizationapi.ExpandResources(rule.Resources)

		if a.resourceMatches(allowedResourceTypes) {
			if a.nameMatches(rule.ResourceNames) {
				// this rule matches the request, so we should check the additional restrictions to be sure that it's allowed
				if rule.AttributeRestrictions.Object != nil {
					switch rule.AttributeRestrictions.Object.(type) {
					case (*authorizationapi.IsPersonalSubjectAccessReview):
						return IsPersonalAccessReview(a)
					default:
						return false, fmt.Errorf("unable to interpret: %#v", rule.AttributeRestrictions.Object)
					}
				}

				return true, nil
			}
		}
	}

	return false, nil
}
// ruleCovers determines whether the ownerRule (which may have multiple verbs, resources, and resourceNames) covers
// the subrule (which may only contain at most one verb, resource, and resourceName)
func ruleCovers(ownerRule, subrule authorizationapi.PolicyRule) bool {
	allResources := authorizationapi.ExpandResources(ownerRule.Resources)

	verbMatches := ownerRule.Verbs.Has("*") || ownerRule.Verbs.HasAll(subrule.Verbs.List()...)
	resourceMatches := ownerRule.Resources.Has("*") || allResources.HasAll(subrule.Resources.List()...)
	resourceNameMatches := false

	if len(subrule.ResourceNames) == 0 {
		resourceNameMatches = (len(ownerRule.ResourceNames) == 0)
	} else {
		resourceNameMatches = (len(ownerRule.ResourceNames) == 0) || ownerRule.ResourceNames.HasAll(subrule.ResourceNames.List()...)
	}

	return verbMatches && resourceMatches && resourceNameMatches
}
// TestAllOpenShiftResourceCoverage checks to make sure that the openshift all group actually contains all openshift resources
func TestAllOpenShiftResourceCoverage(t *testing.T) {
	allOpenshift := authorizationapi.ExpandResources(util.NewStringSet(authorizationapi.GroupsToResources[authorizationapi.OpenshiftAllGroupName]...))

	config := &MasterConfig{
		KubeletClientConfig: &kclient.KubeletConfig{},
	}

	storageMap := config.GetRestStorage()
	for key := range storageMap {
		if allOpenshift.Has(strings.ToLower(key)) {
			continue
		}

		t.Errorf("authorizationapi.GroupsToResources[authorizationapi.OpenshiftAllGroupName] is missing %v.  Check pkg/authorization/api/types.go.", strings.ToLower(key))
	}
}
// breadownRule takes a rule and builds an equivalent list of rules that each have at most one verb, one
// resource, and one resource name
func breakdownRule(rule authorizationapi.PolicyRule) []authorizationapi.PolicyRule {
	subrules := []authorizationapi.PolicyRule{}

	for resource := range authorizationapi.ExpandResources(rule.Resources) {
		for verb := range rule.Verbs {
			if len(rule.ResourceNames) > 0 {
				for _, resourceName := range rule.ResourceNames.List() {
					subrules = append(subrules, authorizationapi.PolicyRule{Resources: util.NewStringSet(resource), Verbs: util.NewStringSet(verb), ResourceNames: util.NewStringSet(resourceName)})
				}

			} else {
				subrules = append(subrules, authorizationapi.PolicyRule{Resources: util.NewStringSet(resource), Verbs: util.NewStringSet(verb)})
			}

		}
	}

	return subrules
}