Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ type Interface interface {
RoleBindingsNamespacer
PolicyBindingsNamespacer
ResourceAccessReviewsNamespacer
RootResourceAccessReviews
ClusterResourceAccessReviews
SubjectAccessReviewsNamespacer
ClusterSubjectAccessReviews
TemplatesNamespacer
TemplateConfigsNamespacer
OAuthAccessTokensInterface
Expand Down Expand Up @@ -176,19 +177,19 @@ func (c *Client) ResourceAccessReviews(namespace string) ResourceAccessReviewInt
return newResourceAccessReviews(c, namespace)
}

// RootResourceAccessReviews provides a REST client for RootResourceAccessReviews
func (c *Client) RootResourceAccessReviews() ResourceAccessReviewInterface {
return newRootResourceAccessReviews(c)
// ClusterResourceAccessReviews provides a REST client for ClusterResourceAccessReviews
func (c *Client) ClusterResourceAccessReviews() ResourceAccessReviewInterface {
return newClusterResourceAccessReviews(c)
}

// SubjectAccessReviews provides a REST client for SubjectAccessReviews
func (c *Client) SubjectAccessReviews(namespace string) SubjectAccessReviewInterface {
return newSubjectAccessReviews(c, namespace)
}

// RootSubjectAccessReviews provides a REST client for RootSubjectAccessReviews
func (c *Client) RootSubjectAccessReviews() SubjectAccessReviewInterface {
return newRootSubjectAccessReviews(c)
// ClusterSubjectAccessReviews provides a REST client for SubjectAccessReviews
func (c *Client) ClusterSubjectAccessReviews() SubjectAccessReviewInterface {
return newClusterSubjectAccessReviews(c)
}

// OAuthAccessTokens provides a REST client for OAuthAccessTokens
Expand Down
8 changes: 6 additions & 2 deletions pkg/client/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ func (c *Fake) ResourceAccessReviews(namespace string) ResourceAccessReviewInter
return &FakeResourceAccessReviews{Fake: c}
}

func (c *Fake) RootResourceAccessReviews() ResourceAccessReviewInterface {
return &FakeRootResourceAccessReviews{Fake: c}
func (c *Fake) ClusterResourceAccessReviews() ResourceAccessReviewInterface {
return &FakeClusterResourceAccessReviews{Fake: c}
}

func (c *Fake) SubjectAccessReviews(namespace string) SubjectAccessReviewInterface {
Expand All @@ -142,4 +142,8 @@ func (c *Fake) SubjectAccessReviews(namespace string) SubjectAccessReviewInterfa

func (c *Fake) OAuthAccessTokens() OAuthAccessTokenInterface {
return &FakeOAuthAccessTokens{Fake: c}

}
func (c *Fake) ClusterSubjectAccessReviews() SubjectAccessReviewInterface {
return &FakeClusterSubjectAccessReviews{Fake: c}
}
9 changes: 9 additions & 0 deletions pkg/client/fake_projectrequests.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package client

import (
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"

projectapi "github.com/openshift/origin/pkg/project/api"
)

Expand All @@ -12,3 +16,8 @@ func (c *FakeProjectRequests) Create(project *projectapi.ProjectRequest) (*proje
obj, err := c.Fake.Invokes(FakeAction{Action: "create-newProject", Value: project}, &projectapi.ProjectRequest{})
return obj.(*projectapi.Project), err
}

func (c *FakeProjectRequests) List(label labels.Selector, field fields.Selector) (*kapi.Status, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "list-newProject"}, &kapi.Status{})
return obj.(*kapi.Status), err
}
6 changes: 3 additions & 3 deletions pkg/client/fake_resourceaccessreview.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ func (c *FakeResourceAccessReviews) Create(resourceAccessReview *authorizationap
return obj.(*authorizationapi.ResourceAccessReviewResponse), err
}

type FakeRootResourceAccessReviews struct {
type FakeClusterResourceAccessReviews struct {
Fake *Fake
}

func (c *FakeRootResourceAccessReviews) Create(resourceAccessReview *authorizationapi.ResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "create-root-resourceAccessReview", Value: resourceAccessReview}, &authorizationapi.ResourceAccessReviewResponse{})
func (c *FakeClusterResourceAccessReviews) Create(resourceAccessReview *authorizationapi.ResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "create-cluster-resourceAccessReview", Value: resourceAccessReview}, &authorizationapi.ResourceAccessReviewResponse{})
return obj.(*authorizationapi.ResourceAccessReviewResponse), err
}
9 changes: 9 additions & 0 deletions pkg/client/fake_subjectaccessreview.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ func (c *FakeSubjectAccessReviews) Create(subjectAccessReview *authorizationapi.
obj, err := c.Fake.Invokes(FakeAction{Action: "create-subjectAccessReview", Value: subjectAccessReview}, &authorizationapi.SubjectAccessReviewResponse{})
return obj.(*authorizationapi.SubjectAccessReviewResponse), err
}

type FakeClusterSubjectAccessReviews struct {
Fake *Fake
}

func (c *FakeClusterSubjectAccessReviews) Create(resourceAccessReview *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
obj, err := c.Fake.Invokes(FakeAction{Action: "create-cluster-subjectAccessReview", Value: resourceAccessReview}, &authorizationapi.SubjectAccessReviewResponse{})
return obj.(*authorizationapi.SubjectAccessReviewResponse), err
}
20 changes: 16 additions & 4 deletions pkg/client/projectrequests.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package client

import (
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"

projectapi "github.com/openshift/origin/pkg/project/api"
_ "github.com/openshift/origin/pkg/user/api/v1beta1"
)
Expand All @@ -13,22 +17,30 @@ type ProjectRequestsInterface interface {
// UserInterface exposes methods on user resources.
type ProjectRequestInterface interface {
Create(p *projectapi.ProjectRequest) (*projectapi.Project, error)
List(label labels.Selector, field fields.Selector) (*kapi.Status, error)
}

type newProjectRequestsStruct struct {
type projectRequests struct {
r *Client
}

// newUsers returns a users
func newProjectRequests(c *Client) *newProjectRequestsStruct {
return &newProjectRequestsStruct{
func newProjectRequests(c *Client) *projectRequests {
return &projectRequests{
r: c,
}
}

// Create creates a new ProjectRequest
func (c *newProjectRequestsStruct) Create(p *projectapi.ProjectRequest) (result *projectapi.Project, err error) {
func (c *projectRequests) Create(p *projectapi.ProjectRequest) (result *projectapi.Project, err error) {
result = &projectapi.Project{}
err = c.r.Post().Resource("projectrequests").Body(p).Do().Into(result)
return
}

// List returns a status object indicating that a user can call the Create or an error indicating why not
func (c *projectRequests) List(label labels.Selector, field fields.Selector) (result *kapi.Status, err error) {
result = &kapi.Status{}
err = c.r.Get().Resource("projectrequests").LabelsSelectorParam(label).FieldsSelectorParam(field).Do().Into(result)
return result, err
}
18 changes: 9 additions & 9 deletions pkg/client/resourceaccessreview.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ type ResourceAccessReviewsNamespacer interface {
ResourceAccessReviews(namespace string) ResourceAccessReviewInterface
}

// RootResourceAccessReviews has methods to work with ResourceAccessReview resources in the root scope
type RootResourceAccessReviews interface {
RootResourceAccessReviews() ResourceAccessReviewInterface
// ClusterResourceAccessReviews has methods to work with ResourceAccessReview resources in the cluster scope
type ClusterResourceAccessReviews interface {
ClusterResourceAccessReviews() ResourceAccessReviewInterface
}

// ResourceAccessReviewInterface exposes methods on ResourceAccessReview resources.
Expand Down Expand Up @@ -40,20 +40,20 @@ func (c *resourceAccessReviews) Create(policy *authorizationapi.ResourceAccessRe
return
}

// rootResourceAccessReviews implements RootResourceAccessReviews interface
type rootResourceAccessReviews struct {
// clusterResourceAccessReviews implements ClusterResourceAccessReviews interface
type clusterResourceAccessReviews struct {
r *Client
}

// newRootResourceAccessReviews returns a rootResourceAccessReviews
func newRootResourceAccessReviews(c *Client) *rootResourceAccessReviews {
return &rootResourceAccessReviews{
// newClusterResourceAccessReviews returns a clusterResourceAccessReviews
func newClusterResourceAccessReviews(c *Client) *clusterResourceAccessReviews {
return &clusterResourceAccessReviews{
r: c,
}
}

// Create creates new policy. Returns the server's representation of the policy and error if one occurs.
func (c *rootResourceAccessReviews) Create(policy *authorizationapi.ResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
func (c *clusterResourceAccessReviews) Create(policy *authorizationapi.ResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
result = &authorizationapi.ResourceAccessReviewResponse{}
err = c.r.Post().Resource("resourceAccessReviews").Body(policy).Do().Into(result)
return
Expand Down
17 changes: 11 additions & 6 deletions pkg/client/subjectaccessreview.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ type SubjectAccessReviewsNamespacer interface {
SubjectAccessReviews(namespace string) SubjectAccessReviewInterface
}

// ClusterSubjectAccessReviews has methods to work with SubjectAccessReview resources in the cluster scope
type ClusterSubjectAccessReviews interface {
ClusterSubjectAccessReviews() SubjectAccessReviewInterface
}

// SubjectAccessReviewInterface exposes methods on SubjectAccessReview resources.
type SubjectAccessReviewInterface interface {
Create(policy *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error)
Expand All @@ -35,20 +40,20 @@ func (c *subjectAccessReviews) Create(policy *authorizationapi.SubjectAccessRevi
return
}

// rootSubjectAccessReviews implements RootSubjectAccessReviews interface
type rootSubjectAccessReviews struct {
// clusterSubjectAccessReviews implements ClusterSubjectAccessReviews interface
type clusterSubjectAccessReviews struct {
r *Client
}

// newRootSubjectAccessReviews returns a rootSubjectAccessReviews
func newRootSubjectAccessReviews(c *Client) *rootSubjectAccessReviews {
return &rootSubjectAccessReviews{
// newClusterSubjectAccessReviews returns a clusterSubjectAccessReviews
func newClusterSubjectAccessReviews(c *Client) *clusterSubjectAccessReviews {
return &clusterSubjectAccessReviews{
r: c,
}
}

// Create creates new policy. Returns the server's representation of the policy and error if one occurs.
func (c *rootSubjectAccessReviews) Create(policy *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReviewResponse, err error) {
func (c *clusterSubjectAccessReviews) Create(policy *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReviewResponse, err error) {
result = &authorizationapi.SubjectAccessReviewResponse{}
err = c.r.Post().Resource("subjectAccessReviews").Body(policy).Do().Into(result)
return
Expand Down
8 changes: 8 additions & 0 deletions pkg/cmd/server/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ type MasterConfig struct {

// PolicyConfig holds information about where to locate critical pieces of bootstrapping policy
PolicyConfig PolicyConfig

// ProjectRequestConfig holds information about how to handle new project requests
ProjectRequestConfig ProjectRequestConfig
}

type ProjectRequestConfig struct {
// ProjectRequestMessage is the string presented to a user if they are unable to request a project via the projectrequest api endpoint
ProjectRequestMessage string
}

type PolicyConfig struct {
Expand Down
8 changes: 8 additions & 0 deletions pkg/cmd/server/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ type MasterConfig struct {
ImageConfig ImageConfig `json:"imageConfig"`

PolicyConfig PolicyConfig `json:"policyConfig"`

// ProjectRequestConfig holds information about how to handle new project requests
ProjectRequestConfig ProjectRequestConfig `json:"projectRequestConfig"`
}

type ProjectRequestConfig struct {
// ProjectRequestMessage is the string presented to a user if they are unable to request a project via the projectrequest api endpoint
ProjectRequestMessage string `json:"projectRequestMessage"`
}

type PolicyConfig struct {
Expand Down
9 changes: 9 additions & 0 deletions pkg/cmd/server/api/validation/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func ValidateMasterConfig(config *api.MasterConfig) fielderrors.ValidationErrorL

allErrs = append(allErrs, ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)

allErrs = append(allErrs, ValidateProjectRequestConfig(config.ProjectRequestConfig).Prefix("projectRequestConfig")...)

return allErrs
}

Expand Down Expand Up @@ -185,3 +187,10 @@ func ValidatePolicyConfig(config api.PolicyConfig) fielderrors.ValidationErrorLi

return allErrs
}

// ValidateProjectRequestConfig is stub for now. no validation is required.
func ValidateProjectRequestConfig(config api.ProjectRequestConfig) fielderrors.ValidationErrorList {
allErrs := fielderrors.ValidationErrorList{}

return allErrs
}
2 changes: 1 addition & 1 deletion pkg/cmd/server/bootstrappolicy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func GetBootstrapMasterRoles(masterNamespace string) []authorizationapi.Role {
},
Rules: []authorizationapi.PolicyRule{
{Verbs: util.NewStringSet("get"), Resources: util.NewStringSet("users"), ResourceNames: util.NewStringSet("~")},
{Verbs: util.NewStringSet("get"), Resources: util.NewStringSet("projectrequests")},
{Verbs: util.NewStringSet("list"), Resources: util.NewStringSet("projectrequests")},
{Verbs: util.NewStringSet("list"), Resources: util.NewStringSet("projects")},
{Verbs: util.NewStringSet("create"), Resources: util.NewStringSet("subjectaccessreviews"), AttributeRestrictions: runtime.EmbeddedObject{&authorizationapi.IsPersonalSubjectAccessReview{}}},
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/server/origin/master.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin
"routes": routeregistry.NewREST(routeEtcd, routeAllocator),

"projects": projectStorage,
"projectRequests": projectrequeststorage.NewREST(c.Options.PolicyConfig.MasterAuthorizationNamespace, roleBindingStorage, *projectStorage),
"projectRequests": projectrequeststorage.NewREST(c.Options.ProjectRequestConfig.ProjectRequestMessage, c.Options.PolicyConfig.MasterAuthorizationNamespace, roleBindingStorage, *projectStorage, c.PolicyClient()),

"users": userStorage,
"identities": identityStorage,
Expand Down
47 changes: 45 additions & 2 deletions pkg/project/registry/projectrequest/delegated/delegated.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,52 @@
package delegated

import (
"errors"

kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
kapierror "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

authorizationapi "github.com/openshift/origin/pkg/authorization/api"
"github.com/openshift/origin/pkg/authorization/registry/rolebinding"
"github.com/openshift/origin/pkg/client"

projectapi "github.com/openshift/origin/pkg/project/api"
projectstorage "github.com/openshift/origin/pkg/project/registry/project/proxy"
projectrequestregistry "github.com/openshift/origin/pkg/project/registry/projectrequest"
)

type REST struct {
message string
masterNamespace string
roleBindingStorage rolebinding.Storage

projectStorage projectstorage.REST
projectStorage projectstorage.REST
openshiftClient *client.Client
}

func NewREST(masterNamespace string, roleBindingStorage rolebinding.Storage, projectStorage projectstorage.REST) *REST {
func NewREST(message, masterNamespace string, roleBindingStorage rolebinding.Storage, projectStorage projectstorage.REST, openshiftClient *client.Client) *REST {
return &REST{
message: message,
masterNamespace: masterNamespace,
roleBindingStorage: roleBindingStorage,
projectStorage: projectStorage,
openshiftClient: openshiftClient,
}
}

func (r *REST) New() runtime.Object {
return &projectapi.ProjectRequest{}
}

func (r *REST) NewList() runtime.Object {
return &kapi.Status{}
}

func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
if err := rest.BeforeCreate(projectrequestregistry.Strategy, ctx, obj); err != nil {
return nil, err
Expand Down Expand Up @@ -65,3 +79,32 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err

return realizedProject, nil
}

func (r *REST) List(ctx kapi.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
userInfo, exists := kapi.UserFrom(ctx)
if !exists {
return nil, errors.New("a user must be provided")
}

// the caller might not have permission to run a subject access review (he has it by default, but it could have been removed).
// So we'll escalate for the subject access review to determine rights
accessReview := &authorizationapi.SubjectAccessReview{
Verb: "create",
Resource: "projectrequests",
User: userInfo.GetName(),
Groups: util.NewStringSet(userInfo.GetGroups()...),
}
accessReviewResponse, err := r.openshiftClient.ClusterSubjectAccessReviews().Create(accessReview)
if err != nil {
return nil, err
}
if accessReviewResponse.Allowed {
return &kapi.Status{Status: kapi.StatusSuccess}, nil
}

forbiddenError, _ := kapierror.NewForbidden("ProjectRequest", "", errors.New("You may not request a new project via this API.")).(*kapierror.StatusError)
if len(r.message) > 0 {
forbiddenError.ErrStatus.Message = r.message
}
return nil, forbiddenError
}
Loading