package rulevalidation import ( kapi "k8s.io/kubernetes/pkg/api" kapierror "k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/auth/user" kerrors "k8s.io/kubernetes/pkg/util/errors" "k8s.io/kubernetes/pkg/util/sets" authorizationapi "github.com/openshift/origin/pkg/authorization/api" authorizationinterfaces "github.com/openshift/origin/pkg/authorization/interfaces" "github.com/openshift/origin/pkg/client" ) type DefaultRuleResolver struct { policyGetter client.PoliciesListerNamespacer bindingLister client.PolicyBindingsListerNamespacer clusterPolicyGetter client.ClusterPolicyLister clusterBindingLister client.ClusterPolicyBindingLister } func NewDefaultRuleResolver(policyGetter client.PoliciesListerNamespacer, bindingLister client.PolicyBindingsListerNamespacer, clusterPolicyGetter client.ClusterPolicyLister, clusterBindingLister client.ClusterPolicyBindingLister) *DefaultRuleResolver { return &DefaultRuleResolver{policyGetter, bindingLister, clusterPolicyGetter, clusterBindingLister} } type AuthorizationRuleResolver interface { GetRoleBindings(namespace string) ([]authorizationinterfaces.RoleBinding, error) GetRole(roleBinding authorizationinterfaces.RoleBinding) (authorizationinterfaces.Role, error) // RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of // PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations // can be made on the basis of those rules that are found. RulesFor(info user.Info, namespace string) ([]authorizationapi.PolicyRule, error) } func (a *DefaultRuleResolver) GetRoleBindings(namespace string) ([]authorizationinterfaces.RoleBinding, error) { clusterBindings, clusterErr := a.clusterBindingLister.List(kapi.ListOptions{}) var namespaceBindings *authorizationapi.PolicyBindingList var namespaceErr error if a.bindingLister != nil && len(namespace) > 0 { namespaceBindings, namespaceErr = a.bindingLister.PolicyBindings(namespace).List(kapi.ListOptions{}) } // return all loaded bindings expect := 0 if clusterBindings != nil { expect += len(clusterBindings.Items) } if namespaceBindings != nil { expect += len(namespaceBindings.Items) } bindings := make([]authorizationinterfaces.RoleBinding, 0, expect) if clusterBindings != nil { for _, policyBinding := range clusterBindings.Items { for _, value := range policyBinding.RoleBindings { bindings = append(bindings, authorizationinterfaces.NewClusterRoleBindingAdapter(value)) } } } if namespaceBindings != nil { for _, policyBinding := range namespaceBindings.Items { for _, value := range policyBinding.RoleBindings { bindings = append(bindings, authorizationinterfaces.NewLocalRoleBindingAdapter(value)) } } } // return all errors var errs []error if clusterErr != nil { errs = append(errs, clusterErr) } if namespaceErr != nil { errs = append(errs, namespaceErr) } return bindings, kerrors.NewAggregate(errs) } func (a *DefaultRuleResolver) GetRole(roleBinding authorizationinterfaces.RoleBinding) (authorizationinterfaces.Role, error) { namespace := roleBinding.RoleRef().Namespace name := roleBinding.RoleRef().Name if len(namespace) == 0 { policy, err := a.clusterPolicyGetter.Get(authorizationapi.PolicyName) if kapierror.IsNotFound(err) { return nil, kapierror.NewNotFound(authorizationapi.Resource("role"), name) } if err != nil { return nil, err } role, exists := policy.Roles[name] if !exists { return nil, kapierror.NewNotFound(authorizationapi.Resource("role"), name) } return authorizationinterfaces.NewClusterRoleAdapter(role), nil } if a.policyGetter == nil { return nil, kapierror.NewNotFound(authorizationapi.Resource("role"), name) } policy, err := a.policyGetter.Policies(namespace).Get(authorizationapi.PolicyName) if kapierror.IsNotFound(err) { return nil, kapierror.NewNotFound(authorizationapi.Resource("role"), name) } if err != nil { return nil, err } role, exists := policy.Roles[name] if !exists { return nil, kapierror.NewNotFound(authorizationapi.Resource("role"), name) } return authorizationinterfaces.NewLocalRoleAdapter(role), nil } // RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of // PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations // can be made on the basis of those rules that are found. func (a *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]authorizationapi.PolicyRule, error) { var errs []error roleBindings, err := a.GetRoleBindings(namespace) if err != nil { errs = append(errs, err) } rules := make([]authorizationapi.PolicyRule, 0, len(roleBindings)) for _, roleBinding := range roleBindings { if !roleBinding.AppliesToUser(user) { continue } role, err := a.GetRole(roleBinding) if err != nil { errs = append(errs, err) continue } for _, curr := range role.Rules() { rules = append(rules, curr) } } return rules, kerrors.NewAggregate(errs) } func appliesToUser(ruleUsers, ruleGroups sets.String, user user.Info) bool { if ruleUsers.Has(user.GetName()) { return true } for _, currGroup := range user.GetGroups() { if ruleGroups.Has(currGroup) { return true } } return false }