Browse code

projectrequest get message

deads2k authored on 2015/04/28 21:11:20
Showing 16 changed files
... ...
@@ -39,8 +39,9 @@ type Interface interface {
39 39
 	RoleBindingsNamespacer
40 40
 	PolicyBindingsNamespacer
41 41
 	ResourceAccessReviewsNamespacer
42
-	RootResourceAccessReviews
42
+	ClusterResourceAccessReviews
43 43
 	SubjectAccessReviewsNamespacer
44
+	ClusterSubjectAccessReviews
44 45
 	TemplatesNamespacer
45 46
 	TemplateConfigsNamespacer
46 47
 	OAuthAccessTokensInterface
... ...
@@ -176,9 +177,9 @@ func (c *Client) ResourceAccessReviews(namespace string) ResourceAccessReviewInt
176 176
 	return newResourceAccessReviews(c, namespace)
177 177
 }
178 178
 
179
-// RootResourceAccessReviews provides a REST client for RootResourceAccessReviews
180
-func (c *Client) RootResourceAccessReviews() ResourceAccessReviewInterface {
181
-	return newRootResourceAccessReviews(c)
179
+// ClusterResourceAccessReviews provides a REST client for ClusterResourceAccessReviews
180
+func (c *Client) ClusterResourceAccessReviews() ResourceAccessReviewInterface {
181
+	return newClusterResourceAccessReviews(c)
182 182
 }
183 183
 
184 184
 // SubjectAccessReviews provides a REST client for SubjectAccessReviews
... ...
@@ -186,9 +187,9 @@ func (c *Client) SubjectAccessReviews(namespace string) SubjectAccessReviewInter
186 186
 	return newSubjectAccessReviews(c, namespace)
187 187
 }
188 188
 
189
-// RootSubjectAccessReviews provides a REST client for RootSubjectAccessReviews
190
-func (c *Client) RootSubjectAccessReviews() SubjectAccessReviewInterface {
191
-	return newRootSubjectAccessReviews(c)
189
+// ClusterSubjectAccessReviews provides a REST client for SubjectAccessReviews
190
+func (c *Client) ClusterSubjectAccessReviews() SubjectAccessReviewInterface {
191
+	return newClusterSubjectAccessReviews(c)
192 192
 }
193 193
 
194 194
 // OAuthAccessTokens provides a REST client for OAuthAccessTokens
... ...
@@ -132,8 +132,8 @@ func (c *Fake) ResourceAccessReviews(namespace string) ResourceAccessReviewInter
132 132
 	return &FakeResourceAccessReviews{Fake: c}
133 133
 }
134 134
 
135
-func (c *Fake) RootResourceAccessReviews() ResourceAccessReviewInterface {
136
-	return &FakeRootResourceAccessReviews{Fake: c}
135
+func (c *Fake) ClusterResourceAccessReviews() ResourceAccessReviewInterface {
136
+	return &FakeClusterResourceAccessReviews{Fake: c}
137 137
 }
138 138
 
139 139
 func (c *Fake) SubjectAccessReviews(namespace string) SubjectAccessReviewInterface {
... ...
@@ -142,4 +142,8 @@ func (c *Fake) SubjectAccessReviews(namespace string) SubjectAccessReviewInterfa
142 142
 
143 143
 func (c *Fake) OAuthAccessTokens() OAuthAccessTokenInterface {
144 144
 	return &FakeOAuthAccessTokens{Fake: c}
145
+
146
+}
147
+func (c *Fake) ClusterSubjectAccessReviews() SubjectAccessReviewInterface {
148
+	return &FakeClusterSubjectAccessReviews{Fake: c}
145 149
 }
... ...
@@ -1,6 +1,10 @@
1 1
 package client
2 2
 
3 3
 import (
4
+	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
6
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
7
+
4 8
 	projectapi "github.com/openshift/origin/pkg/project/api"
5 9
 )
6 10
 
... ...
@@ -12,3 +16,8 @@ func (c *FakeProjectRequests) Create(project *projectapi.ProjectRequest) (*proje
12 12
 	obj, err := c.Fake.Invokes(FakeAction{Action: "create-newProject", Value: project}, &projectapi.ProjectRequest{})
13 13
 	return obj.(*projectapi.Project), err
14 14
 }
15
+
16
+func (c *FakeProjectRequests) List(label labels.Selector, field fields.Selector) (*kapi.Status, error) {
17
+	obj, err := c.Fake.Invokes(FakeAction{Action: "list-newProject"}, &kapi.Status{})
18
+	return obj.(*kapi.Status), err
19
+}
... ...
@@ -13,11 +13,11 @@ func (c *FakeResourceAccessReviews) Create(resourceAccessReview *authorizationap
13 13
 	return obj.(*authorizationapi.ResourceAccessReviewResponse), err
14 14
 }
15 15
 
16
-type FakeRootResourceAccessReviews struct {
16
+type FakeClusterResourceAccessReviews struct {
17 17
 	Fake *Fake
18 18
 }
19 19
 
20
-func (c *FakeRootResourceAccessReviews) Create(resourceAccessReview *authorizationapi.ResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error) {
21
-	obj, err := c.Fake.Invokes(FakeAction{Action: "create-root-resourceAccessReview", Value: resourceAccessReview}, &authorizationapi.ResourceAccessReviewResponse{})
20
+func (c *FakeClusterResourceAccessReviews) Create(resourceAccessReview *authorizationapi.ResourceAccessReview) (*authorizationapi.ResourceAccessReviewResponse, error) {
21
+	obj, err := c.Fake.Invokes(FakeAction{Action: "create-cluster-resourceAccessReview", Value: resourceAccessReview}, &authorizationapi.ResourceAccessReviewResponse{})
22 22
 	return obj.(*authorizationapi.ResourceAccessReviewResponse), err
23 23
 }
... ...
@@ -12,3 +12,12 @@ func (c *FakeSubjectAccessReviews) Create(subjectAccessReview *authorizationapi.
12 12
 	obj, err := c.Fake.Invokes(FakeAction{Action: "create-subjectAccessReview", Value: subjectAccessReview}, &authorizationapi.SubjectAccessReviewResponse{})
13 13
 	return obj.(*authorizationapi.SubjectAccessReviewResponse), err
14 14
 }
15
+
16
+type FakeClusterSubjectAccessReviews struct {
17
+	Fake *Fake
18
+}
19
+
20
+func (c *FakeClusterSubjectAccessReviews) Create(resourceAccessReview *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error) {
21
+	obj, err := c.Fake.Invokes(FakeAction{Action: "create-cluster-subjectAccessReview", Value: resourceAccessReview}, &authorizationapi.SubjectAccessReviewResponse{})
22
+	return obj.(*authorizationapi.SubjectAccessReviewResponse), err
23
+}
... ...
@@ -1,6 +1,10 @@
1 1
 package client
2 2
 
3 3
 import (
4
+	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
5
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
6
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
7
+
4 8
 	projectapi "github.com/openshift/origin/pkg/project/api"
5 9
 	_ "github.com/openshift/origin/pkg/user/api/v1beta1"
6 10
 )
... ...
@@ -13,22 +17,30 @@ type ProjectRequestsInterface interface {
13 13
 // UserInterface exposes methods on user resources.
14 14
 type ProjectRequestInterface interface {
15 15
 	Create(p *projectapi.ProjectRequest) (*projectapi.Project, error)
16
+	List(label labels.Selector, field fields.Selector) (*kapi.Status, error)
16 17
 }
17 18
 
18
-type newProjectRequestsStruct struct {
19
+type projectRequests struct {
19 20
 	r *Client
20 21
 }
21 22
 
22 23
 // newUsers returns a users
23
-func newProjectRequests(c *Client) *newProjectRequestsStruct {
24
-	return &newProjectRequestsStruct{
24
+func newProjectRequests(c *Client) *projectRequests {
25
+	return &projectRequests{
25 26
 		r: c,
26 27
 	}
27 28
 }
28 29
 
29 30
 // Create creates a new ProjectRequest
30
-func (c *newProjectRequestsStruct) Create(p *projectapi.ProjectRequest) (result *projectapi.Project, err error) {
31
+func (c *projectRequests) Create(p *projectapi.ProjectRequest) (result *projectapi.Project, err error) {
31 32
 	result = &projectapi.Project{}
32 33
 	err = c.r.Post().Resource("projectrequests").Body(p).Do().Into(result)
33 34
 	return
34 35
 }
36
+
37
+// List returns a status object indicating that a user can call the Create or an error indicating why not
38
+func (c *projectRequests) List(label labels.Selector, field fields.Selector) (result *kapi.Status, err error) {
39
+	result = &kapi.Status{}
40
+	err = c.r.Get().Resource("projectrequests").LabelsSelectorParam(label).FieldsSelectorParam(field).Do().Into(result)
41
+	return result, err
42
+}
... ...
@@ -9,9 +9,9 @@ type ResourceAccessReviewsNamespacer interface {
9 9
 	ResourceAccessReviews(namespace string) ResourceAccessReviewInterface
10 10
 }
11 11
 
12
-// RootResourceAccessReviews has methods to work with ResourceAccessReview resources in the root scope
13
-type RootResourceAccessReviews interface {
14
-	RootResourceAccessReviews() ResourceAccessReviewInterface
12
+// ClusterResourceAccessReviews has methods to work with ResourceAccessReview resources in the cluster scope
13
+type ClusterResourceAccessReviews interface {
14
+	ClusterResourceAccessReviews() ResourceAccessReviewInterface
15 15
 }
16 16
 
17 17
 // ResourceAccessReviewInterface exposes methods on ResourceAccessReview resources.
... ...
@@ -40,20 +40,20 @@ func (c *resourceAccessReviews) Create(policy *authorizationapi.ResourceAccessRe
40 40
 	return
41 41
 }
42 42
 
43
-// rootResourceAccessReviews implements RootResourceAccessReviews interface
44
-type rootResourceAccessReviews struct {
43
+// clusterResourceAccessReviews implements ClusterResourceAccessReviews interface
44
+type clusterResourceAccessReviews struct {
45 45
 	r *Client
46 46
 }
47 47
 
48
-// newRootResourceAccessReviews returns a rootResourceAccessReviews
49
-func newRootResourceAccessReviews(c *Client) *rootResourceAccessReviews {
50
-	return &rootResourceAccessReviews{
48
+// newClusterResourceAccessReviews returns a clusterResourceAccessReviews
49
+func newClusterResourceAccessReviews(c *Client) *clusterResourceAccessReviews {
50
+	return &clusterResourceAccessReviews{
51 51
 		r: c,
52 52
 	}
53 53
 }
54 54
 
55 55
 // Create creates new policy. Returns the server's representation of the policy and error if one occurs.
56
-func (c *rootResourceAccessReviews) Create(policy *authorizationapi.ResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
56
+func (c *clusterResourceAccessReviews) Create(policy *authorizationapi.ResourceAccessReview) (result *authorizationapi.ResourceAccessReviewResponse, err error) {
57 57
 	result = &authorizationapi.ResourceAccessReviewResponse{}
58 58
 	err = c.r.Post().Resource("resourceAccessReviews").Body(policy).Do().Into(result)
59 59
 	return
... ...
@@ -9,6 +9,11 @@ type SubjectAccessReviewsNamespacer interface {
9 9
 	SubjectAccessReviews(namespace string) SubjectAccessReviewInterface
10 10
 }
11 11
 
12
+// ClusterSubjectAccessReviews has methods to work with SubjectAccessReview resources in the cluster scope
13
+type ClusterSubjectAccessReviews interface {
14
+	ClusterSubjectAccessReviews() SubjectAccessReviewInterface
15
+}
16
+
12 17
 // SubjectAccessReviewInterface exposes methods on SubjectAccessReview resources.
13 18
 type SubjectAccessReviewInterface interface {
14 19
 	Create(policy *authorizationapi.SubjectAccessReview) (*authorizationapi.SubjectAccessReviewResponse, error)
... ...
@@ -35,20 +40,20 @@ func (c *subjectAccessReviews) Create(policy *authorizationapi.SubjectAccessRevi
35 35
 	return
36 36
 }
37 37
 
38
-// rootSubjectAccessReviews implements RootSubjectAccessReviews interface
39
-type rootSubjectAccessReviews struct {
38
+// clusterSubjectAccessReviews implements ClusterSubjectAccessReviews interface
39
+type clusterSubjectAccessReviews struct {
40 40
 	r *Client
41 41
 }
42 42
 
43
-// newRootSubjectAccessReviews returns a rootSubjectAccessReviews
44
-func newRootSubjectAccessReviews(c *Client) *rootSubjectAccessReviews {
45
-	return &rootSubjectAccessReviews{
43
+// newClusterSubjectAccessReviews returns a clusterSubjectAccessReviews
44
+func newClusterSubjectAccessReviews(c *Client) *clusterSubjectAccessReviews {
45
+	return &clusterSubjectAccessReviews{
46 46
 		r: c,
47 47
 	}
48 48
 }
49 49
 
50 50
 // Create creates new policy. Returns the server's representation of the policy and error if one occurs.
51
-func (c *rootSubjectAccessReviews) Create(policy *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReviewResponse, err error) {
51
+func (c *clusterSubjectAccessReviews) Create(policy *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReviewResponse, err error) {
52 52
 	result = &authorizationapi.SubjectAccessReviewResponse{}
53 53
 	err = c.r.Post().Resource("subjectAccessReviews").Body(policy).Do().Into(result)
54 54
 	return
... ...
@@ -84,6 +84,14 @@ type MasterConfig struct {
84 84
 
85 85
 	// PolicyConfig holds information about where to locate critical pieces of bootstrapping policy
86 86
 	PolicyConfig PolicyConfig
87
+
88
+	// ProjectRequestConfig holds information about how to handle new project requests
89
+	ProjectRequestConfig ProjectRequestConfig
90
+}
91
+
92
+type ProjectRequestConfig struct {
93
+	// ProjectRequestMessage is the string presented to a user if they are unable to request a project via the projectrequest api endpoint
94
+	ProjectRequestMessage string
87 95
 }
88 96
 
89 97
 type PolicyConfig struct {
... ...
@@ -80,6 +80,14 @@ type MasterConfig struct {
80 80
 	ImageConfig ImageConfig `json:"imageConfig"`
81 81
 
82 82
 	PolicyConfig PolicyConfig `json:"policyConfig"`
83
+
84
+	// ProjectRequestConfig holds information about how to handle new project requests
85
+	ProjectRequestConfig ProjectRequestConfig `json:"projectRequestConfig"`
86
+}
87
+
88
+type ProjectRequestConfig struct {
89
+	// ProjectRequestMessage is the string presented to a user if they are unable to request a project via the projectrequest api endpoint
90
+	ProjectRequestMessage string `json:"projectRequestMessage"`
83 91
 }
84 92
 
85 93
 type PolicyConfig struct {
... ...
@@ -81,6 +81,8 @@ func ValidateMasterConfig(config *api.MasterConfig) fielderrors.ValidationErrorL
81 81
 
82 82
 	allErrs = append(allErrs, ValidateServingInfo(config.ServingInfo).Prefix("servingInfo")...)
83 83
 
84
+	allErrs = append(allErrs, ValidateProjectRequestConfig(config.ProjectRequestConfig).Prefix("projectRequestConfig")...)
85
+
84 86
 	return allErrs
85 87
 }
86 88
 
... ...
@@ -185,3 +187,10 @@ func ValidatePolicyConfig(config api.PolicyConfig) fielderrors.ValidationErrorLi
185 185
 
186 186
 	return allErrs
187 187
 }
188
+
189
+// ValidateProjectRequestConfig is stub for now.  no validation is required.
190
+func ValidateProjectRequestConfig(config api.ProjectRequestConfig) fielderrors.ValidationErrorList {
191
+	allErrs := fielderrors.ValidationErrorList{}
192
+
193
+	return allErrs
194
+}
... ...
@@ -102,7 +102,7 @@ func GetBootstrapMasterRoles(masterNamespace string) []authorizationapi.Role {
102 102
 			},
103 103
 			Rules: []authorizationapi.PolicyRule{
104 104
 				{Verbs: util.NewStringSet("get"), Resources: util.NewStringSet("users"), ResourceNames: util.NewStringSet("~")},
105
-				{Verbs: util.NewStringSet("get"), Resources: util.NewStringSet("projectrequests")},
105
+				{Verbs: util.NewStringSet("list"), Resources: util.NewStringSet("projectrequests")},
106 106
 				{Verbs: util.NewStringSet("list"), Resources: util.NewStringSet("projects")},
107 107
 				{Verbs: util.NewStringSet("create"), Resources: util.NewStringSet("subjectaccessreviews"), AttributeRestrictions: runtime.EmbeddedObject{&authorizationapi.IsPersonalSubjectAccessReview{}}},
108 108
 			},
... ...
@@ -242,7 +242,7 @@ func (c *MasterConfig) InstallProtectedAPI(container *restful.Container) []strin
242 242
 		"routes": routeregistry.NewREST(routeEtcd, routeAllocator),
243 243
 
244 244
 		"projects":        projectStorage,
245
-		"projectRequests": projectrequeststorage.NewREST(c.Options.PolicyConfig.MasterAuthorizationNamespace, roleBindingStorage, *projectStorage),
245
+		"projectRequests": projectrequeststorage.NewREST(c.Options.ProjectRequestConfig.ProjectRequestMessage, c.Options.PolicyConfig.MasterAuthorizationNamespace, roleBindingStorage, *projectStorage, c.PolicyClient()),
246 246
 
247 247
 		"users":                userStorage,
248 248
 		"identities":           identityStorage,
... ...
@@ -1,13 +1,19 @@
1 1
 package delegated
2 2
 
3 3
 import (
4
+	"errors"
5
+
4 6
 	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
7
+	kapierror "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
5 8
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
9
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
10
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
6 11
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
7 12
 	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
8 13
 
9 14
 	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
10 15
 	"github.com/openshift/origin/pkg/authorization/registry/rolebinding"
16
+	"github.com/openshift/origin/pkg/client"
11 17
 
12 18
 	projectapi "github.com/openshift/origin/pkg/project/api"
13 19
 	projectstorage "github.com/openshift/origin/pkg/project/registry/project/proxy"
... ...
@@ -15,17 +21,21 @@ import (
15 15
 )
16 16
 
17 17
 type REST struct {
18
+	message            string
18 19
 	masterNamespace    string
19 20
 	roleBindingStorage rolebinding.Storage
20 21
 
21
-	projectStorage projectstorage.REST
22
+	projectStorage  projectstorage.REST
23
+	openshiftClient *client.Client
22 24
 }
23 25
 
24
-func NewREST(masterNamespace string, roleBindingStorage rolebinding.Storage, projectStorage projectstorage.REST) *REST {
26
+func NewREST(message, masterNamespace string, roleBindingStorage rolebinding.Storage, projectStorage projectstorage.REST, openshiftClient *client.Client) *REST {
25 27
 	return &REST{
28
+		message:            message,
26 29
 		masterNamespace:    masterNamespace,
27 30
 		roleBindingStorage: roleBindingStorage,
28 31
 		projectStorage:     projectStorage,
32
+		openshiftClient:    openshiftClient,
29 33
 	}
30 34
 }
31 35
 
... ...
@@ -33,6 +43,10 @@ func (r *REST) New() runtime.Object {
33 33
 	return &projectapi.ProjectRequest{}
34 34
 }
35 35
 
36
+func (r *REST) NewList() runtime.Object {
37
+	return &kapi.Status{}
38
+}
39
+
36 40
 func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
37 41
 	if err := rest.BeforeCreate(projectrequestregistry.Strategy, ctx, obj); err != nil {
38 42
 		return nil, err
... ...
@@ -65,3 +79,32 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
65 65
 
66 66
 	return realizedProject, nil
67 67
 }
68
+
69
+func (r *REST) List(ctx kapi.Context, label labels.Selector, field fields.Selector) (runtime.Object, error) {
70
+	userInfo, exists := kapi.UserFrom(ctx)
71
+	if !exists {
72
+		return nil, errors.New("a user must be provided")
73
+	}
74
+
75
+	// the caller might not have permission to run a subject access review (he has it by default, but it could have been removed).
76
+	// So we'll escalate for the subject access review to determine rights
77
+	accessReview := &authorizationapi.SubjectAccessReview{
78
+		Verb:     "create",
79
+		Resource: "projectrequests",
80
+		User:     userInfo.GetName(),
81
+		Groups:   util.NewStringSet(userInfo.GetGroups()...),
82
+	}
83
+	accessReviewResponse, err := r.openshiftClient.ClusterSubjectAccessReviews().Create(accessReview)
84
+	if err != nil {
85
+		return nil, err
86
+	}
87
+	if accessReviewResponse.Allowed {
88
+		return &kapi.Status{Status: kapi.StatusSuccess}, nil
89
+	}
90
+
91
+	forbiddenError, _ := kapierror.NewForbidden("ProjectRequest", "", errors.New("You may not request a new project via this API.")).(*kapierror.StatusError)
92
+	if len(r.message) > 0 {
93
+		forbiddenError.ErrStatus.Message = r.message
94
+	}
95
+	return nil, forbiddenError
96
+}
... ...
@@ -246,7 +246,7 @@ func TestResourceAccessReview(t *testing.T) {
246 246
 	// mark should not be able to make global access review requests
247 247
 	{
248 248
 		test := resourceAccessReviewTest{
249
-			clientInterface: markClient.RootResourceAccessReviews(),
249
+			clientInterface: markClient.ClusterResourceAccessReviews(),
250 250
 			review:          requestWhoCanViewDeployments,
251 251
 			err:             "forbidden",
252 252
 		}
... ...
@@ -256,7 +256,7 @@ func TestResourceAccessReview(t *testing.T) {
256 256
 	// a cluster-admin should be able to make global access review requests
257 257
 	{
258 258
 		test := resourceAccessReviewTest{
259
-			clientInterface: clusterAdminClient.RootResourceAccessReviews(),
259
+			clientInterface: clusterAdminClient.ClusterResourceAccessReviews(),
260 260
 			review:          requestWhoCanViewDeployments,
261 261
 			response: authorizationapi.ResourceAccessReviewResponse{
262 262
 				Users:  globalClusterAdminUsers,
... ...
@@ -391,7 +391,7 @@ func TestSubjectAccessReview(t *testing.T) {
391 391
 
392 392
 	askCanClusterAdminsCreateProject := &authorizationapi.SubjectAccessReview{Groups: util.NewStringSet("system:cluster-admins"), Verb: "create", Resource: "projects"}
393 393
 	subjectAccessReviewTest{
394
-		clientInterface: clusterAdminClient.RootSubjectAccessReviews(),
394
+		clientInterface: clusterAdminClient.ClusterSubjectAccessReviews(),
395 395
 		review:          askCanClusterAdminsCreateProject,
396 396
 		response: authorizationapi.SubjectAccessReviewResponse{
397 397
 			Allowed:   true,
... ...
@@ -400,7 +400,7 @@ func TestSubjectAccessReview(t *testing.T) {
400 400
 		},
401 401
 	}.run(t)
402 402
 	subjectAccessReviewTest{
403
-		clientInterface: haroldClient.RootSubjectAccessReviews(),
403
+		clientInterface: haroldClient.ClusterSubjectAccessReviews(),
404 404
 		review:          askCanClusterAdminsCreateProject,
405 405
 		err:             "forbidden",
406 406
 	}.run(t)
... ...
@@ -7,9 +7,14 @@ import (
7 7
 	"testing"
8 8
 	"time"
9 9
 
10
-	"github.com/openshift/origin/pkg/client"
10
+	kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
11
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
12
+	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
11 13
 
14
+	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
15
+	"github.com/openshift/origin/pkg/client"
12 16
 	osc "github.com/openshift/origin/pkg/cmd/cli/cmd"
17
+	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
13 18
 	"github.com/openshift/origin/pkg/cmd/util/tokencmd"
14 19
 	testutil "github.com/openshift/origin/test/util"
15 20
 )
... ...
@@ -45,6 +50,15 @@ func TestUnprivilegedNewProject(t *testing.T) {
45 45
 		t.Fatalf("unexpected error: %v", err)
46 46
 	}
47 47
 
48
+	// confirm that we have access to request the project
49
+	allowed, err := valerieOpenshiftClient.ProjectRequests().List(labels.Everything(), fields.Everything())
50
+	if err != nil {
51
+		t.Errorf("unexpected error: %v", err)
52
+	}
53
+	if allowed.Status != kapi.StatusSuccess {
54
+		t.Errorf("expected %v, got %v", kapi.StatusSuccess, allowed.Status)
55
+	}
56
+
48 57
 	requestProject := osc.NewProjectOptions{
49 58
 		ProjectName: "new-project",
50 59
 		DisplayName: "display name here",
... ...
@@ -60,3 +74,57 @@ func TestUnprivilegedNewProject(t *testing.T) {
60 60
 
61 61
 	waitForProject(t, valerieOpenshiftClient, "new-project", 5*time.Second, 10)
62 62
 }
63
+
64
+func TestDeniedUnprivilegedNewProject(t *testing.T) {
65
+	_, clusterAdminKubeConfig, err := testutil.StartTestMaster()
66
+	if err != nil {
67
+		t.Fatalf("unexpected error: %v", err)
68
+	}
69
+
70
+	clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig)
71
+	if err != nil {
72
+		t.Errorf("unexpected error: %v", err)
73
+	}
74
+	role, err := clusterAdminClient.Roles("master").Get(bootstrappolicy.SelfProvisionerRoleName)
75
+	if err != nil {
76
+		t.Errorf("unexpected error: %v", err)
77
+	}
78
+	role.Rules = []authorizationapi.PolicyRule{}
79
+	clusterAdminClient.Roles("master").Update(role)
80
+
81
+	clusterAdminClientConfig, err := testutil.GetClusterAdminClientConfig(clusterAdminKubeConfig)
82
+	if err != nil {
83
+		t.Errorf("unexpected error: %v", err)
84
+	}
85
+
86
+	valerieClientConfig := *clusterAdminClientConfig
87
+	valerieClientConfig.Username = ""
88
+	valerieClientConfig.Password = ""
89
+	valerieClientConfig.BearerToken = ""
90
+	valerieClientConfig.CertFile = ""
91
+	valerieClientConfig.KeyFile = ""
92
+	valerieClientConfig.CertData = nil
93
+	valerieClientConfig.KeyData = nil
94
+
95
+	accessToken, err := tokencmd.RequestToken(&valerieClientConfig, nil, "valerie", "security!")
96
+	if err != nil {
97
+		t.Fatalf("unexpected error: %v", err)
98
+	}
99
+
100
+	valerieClientConfig.BearerToken = accessToken
101
+	valerieOpenshiftClient, err := client.New(&valerieClientConfig)
102
+	if err != nil {
103
+		t.Fatalf("unexpected error: %v", err)
104
+	}
105
+
106
+	// confirm that we have access to request the project
107
+	allowed, err := valerieOpenshiftClient.ProjectRequests().List(labels.Everything(), fields.Everything())
108
+	if err == nil {
109
+		t.Errorf("expected error: %v", err)
110
+	}
111
+	expectedError := `ProjectRequest "" is forbidden: You may not request a new project via this API.`
112
+	if err.Error() != expectedError {
113
+		t.Errorf("expected %v, got %v", expectedError, allowed.Status)
114
+	}
115
+
116
+}