Add system:authenticated group
| ... | ... |
@@ -25,3 +25,9 @@ type Assertion interface {
|
| 25 | 25 |
type Client interface {
|
| 26 | 26 |
AuthenticateClient(client api.Client) (api.UserInfo, bool, error) |
| 27 | 27 |
} |
| 28 |
+ |
|
| 29 |
+type RequestFunc func(req *http.Request) (api.UserInfo, bool, error) |
|
| 30 |
+ |
|
| 31 |
+func (f RequestFunc) AuthenticateRequest(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 32 |
+ return f(req) |
|
| 33 |
+} |
| 28 | 34 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,31 @@ |
| 0 |
+package bearertoken |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/http" |
|
| 4 |
+ "strings" |
|
| 5 |
+ |
|
| 6 |
+ "github.com/openshift/origin/pkg/auth/api" |
|
| 7 |
+ "github.com/openshift/origin/pkg/auth/authenticator" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+type Authenticator struct {
|
|
| 11 |
+ auth authenticator.Token |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+func New(auth authenticator.Token) *Authenticator {
|
|
| 15 |
+ return &Authenticator{auth}
|
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+func (a *Authenticator) AuthenticateRequest(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 19 |
+ auth := strings.TrimSpace(req.Header.Get("Authorization"))
|
|
| 20 |
+ if auth == "" {
|
|
| 21 |
+ return nil, false, nil |
|
| 22 |
+ } |
|
| 23 |
+ parts := strings.Split(auth, " ") |
|
| 24 |
+ if len(parts) < 2 || strings.ToLower(parts[0]) != "bearer" {
|
|
| 25 |
+ return nil, false, nil |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ token := parts[1] |
|
| 29 |
+ return a.auth.AuthenticateToken(token) |
|
| 30 |
+} |
| 0 | 31 |
deleted file mode 100644 |
| ... | ... |
@@ -1,31 +0,0 @@ |
| 1 |
-package bearertoken |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "net/http" |
|
| 5 |
- "strings" |
|
| 6 |
- |
|
| 7 |
- "github.com/openshift/origin/pkg/auth/api" |
|
| 8 |
- "github.com/openshift/origin/pkg/auth/authenticator" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-type Authenticator struct {
|
|
| 12 |
- auth authenticator.Token |
|
| 13 |
-} |
|
| 14 |
- |
|
| 15 |
-func New(auth authenticator.Token) *Authenticator {
|
|
| 16 |
- return &Authenticator{auth}
|
|
| 17 |
-} |
|
| 18 |
- |
|
| 19 |
-func (a *Authenticator) AuthenticateRequest(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 20 |
- auth := strings.TrimSpace(req.Header.Get("Authorization"))
|
|
| 21 |
- if auth == "" {
|
|
| 22 |
- return nil, false, nil |
|
| 23 |
- } |
|
| 24 |
- parts := strings.Split(auth, " ") |
|
| 25 |
- if len(parts) < 2 || strings.ToLower(parts[0]) != "bearer" {
|
|
| 26 |
- return nil, false, nil |
|
| 27 |
- } |
|
| 28 |
- |
|
| 29 |
- token := parts[1] |
|
| 30 |
- return a.auth.AuthenticateToken(token) |
|
| 31 |
-} |
| 32 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,32 @@ |
| 0 |
+package group |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/http" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/openshift/origin/pkg/auth/api" |
|
| 6 |
+ "github.com/openshift/origin/pkg/auth/authenticator" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+// GroupAdder wraps a request authenticator, and adds the specified groups to the returned user when authentication succeeds |
|
| 10 |
+type GroupAdder struct {
|
|
| 11 |
+ Authenticator authenticator.Request |
|
| 12 |
+ Groups []string |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+func (g *GroupAdder) AuthenticateRequest(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 16 |
+ user, ok, err := g.Authenticator.AuthenticateRequest(req) |
|
| 17 |
+ if err != nil || !ok {
|
|
| 18 |
+ return nil, ok, err |
|
| 19 |
+ } |
|
| 20 |
+ return &api.DefaultUserInfo{
|
|
| 21 |
+ Name: user.GetName(), |
|
| 22 |
+ UID: user.GetUID(), |
|
| 23 |
+ Groups: append(user.GetGroups(), g.Groups...), |
|
| 24 |
+ Scope: user.GetScope(), |
|
| 25 |
+ Extra: user.GetExtra(), |
|
| 26 |
+ }, true, nil |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+func NewGroupAdder(auth authenticator.Request, groups []string) *GroupAdder {
|
|
| 30 |
+ return &GroupAdder{auth, groups}
|
|
| 31 |
+} |
| 0 | 32 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,26 @@ |
| 0 |
+package group |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "net/http" |
|
| 4 |
+ "reflect" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/openshift/origin/pkg/auth/api" |
|
| 8 |
+ "github.com/openshift/origin/pkg/auth/authenticator" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+func TestGroupAdder(t *testing.T) {
|
|
| 12 |
+ adder := authenticator.Request( |
|
| 13 |
+ NewGroupAdder( |
|
| 14 |
+ authenticator.RequestFunc(func(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 15 |
+ return &api.DefaultUserInfo{Name: "user", Groups: []string{"original"}}, true, nil
|
|
| 16 |
+ }), |
|
| 17 |
+ []string{"added"},
|
|
| 18 |
+ ), |
|
| 19 |
+ ) |
|
| 20 |
+ |
|
| 21 |
+ user, _, _ := adder.AuthenticateRequest(nil) |
|
| 22 |
+ if !reflect.DeepEqual(user.GetGroups(), []string{"original", "added"}) {
|
|
| 23 |
+ t.Errorf("Expected original,added groups, got %#v", user.GetGroups())
|
|
| 24 |
+ } |
|
| 25 |
+} |
| ... | ... |
@@ -22,9 +22,9 @@ import ( |
| 22 | 22 |
"github.com/openshift/origin/pkg/auth/authenticator/password/allowanypassword" |
| 23 | 23 |
"github.com/openshift/origin/pkg/auth/authenticator/password/basicauthpassword" |
| 24 | 24 |
"github.com/openshift/origin/pkg/auth/authenticator/request/basicauthrequest" |
| 25 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/bearertoken" |
|
| 25 | 26 |
"github.com/openshift/origin/pkg/auth/authenticator/request/headerrequest" |
| 26 | 27 |
"github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" |
| 27 |
- "github.com/openshift/origin/pkg/auth/authenticator/token/bearertoken" |
|
| 28 | 28 |
"github.com/openshift/origin/pkg/auth/authenticator/token/filetoken" |
| 29 | 29 |
"github.com/openshift/origin/pkg/auth/oauth/external" |
| 30 | 30 |
"github.com/openshift/origin/pkg/auth/oauth/external/github" |
| ... | ... |
@@ -391,13 +391,9 @@ func wrapHandlerWithAuthentication(handler http.Handler, authenticator authentic |
| 391 | 391 |
requestsToUsers, |
| 392 | 392 |
authenticator, |
| 393 | 393 |
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
| 394 |
- // TODO: make this failure handler actually fail once internal components can get auth tokens to do their job |
|
| 395 |
- // w.WriteHeader(http.StatusUnauthorized) |
|
| 396 |
- // return |
|
| 397 |
- |
|
| 398 |
- // For now, just let us know and continue on your merry way |
|
| 399 |
- glog.V(2).Infof("Token authentication failed when accessing: %v", req.URL)
|
|
| 400 |
- handler.ServeHTTP(w, req) |
|
| 394 |
+ w.WriteHeader(http.StatusUnauthorized) |
|
| 395 |
+ w.Write([]byte("Unauthorized"))
|
|
| 396 |
+ return |
|
| 401 | 397 |
}), |
| 402 | 398 |
handler) |
| 403 | 399 |
} |
| ... | ... |
@@ -27,7 +27,12 @@ import ( |
| 27 | 27 |
"github.com/spf13/cobra" |
| 28 | 28 |
|
| 29 | 29 |
"github.com/openshift/origin/pkg/api/latest" |
| 30 |
- "github.com/openshift/origin/pkg/auth/authenticator/token/bearertoken" |
|
| 30 |
+ "github.com/openshift/origin/pkg/auth/api" |
|
| 31 |
+ "github.com/openshift/origin/pkg/auth/authenticator" |
|
| 32 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/bearertoken" |
|
| 33 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/unionrequest" |
|
| 34 |
+ "github.com/openshift/origin/pkg/auth/authenticator/request/x509request" |
|
| 35 |
+ "github.com/openshift/origin/pkg/auth/group" |
|
| 31 | 36 |
"github.com/openshift/origin/pkg/cmd/flagtypes" |
| 32 | 37 |
"github.com/openshift/origin/pkg/cmd/server/crypto" |
| 33 | 38 |
"github.com/openshift/origin/pkg/cmd/server/etcd" |
| ... | ... |
@@ -69,6 +74,13 @@ You may also pass --etcd to connect to an external etcd server instead of runnin |
| 69 | 69 |
instance. |
| 70 | 70 |
` |
| 71 | 71 |
|
| 72 |
+const ( |
|
| 73 |
+ unauthenticatedUsername = "system:anonymous" |
|
| 74 |
+ |
|
| 75 |
+ authenticatedGroup = "system:authenticated" |
|
| 76 |
+ unauthenticatedGroup = "system:unauthenticated" |
|
| 77 |
+) |
|
| 78 |
+ |
|
| 72 | 79 |
// config is a struct that the command stores flag values into. |
| 73 | 80 |
type config struct {
|
| 74 | 81 |
Docker *docker.Helper |
| ... | ... |
@@ -299,11 +311,12 @@ func start(cfg *config, args []string) error {
|
| 299 | 299 |
} |
| 300 | 300 |
|
| 301 | 301 |
// Build token auth for user's OAuth tokens |
| 302 |
+ authenticators := []authenticator.Request{}
|
|
| 302 | 303 |
tokenAuthenticator, err := origin.GetTokenAuthenticator(etcdHelper) |
| 303 | 304 |
if err != nil {
|
| 304 | 305 |
glog.Fatalf("Error creating TokenAuthenticator: %v", err)
|
| 305 | 306 |
} |
| 306 |
- osmaster.Authenticator = bearertoken.New(tokenAuthenticator) |
|
| 307 |
+ authenticators = append(authenticators, group.NewGroupAdder(bearertoken.New(tokenAuthenticator), []string{authenticatedGroup}))
|
|
| 307 | 308 |
|
| 308 | 309 |
var roots *x509.CertPool |
| 309 | 310 |
if osmaster.TLS {
|
| ... | ... |
@@ -355,6 +368,14 @@ func start(cfg *config, args []string) error {
|
| 355 | 355 |
for _, root := range ca.Config.Roots {
|
| 356 | 356 |
roots.AddCert(root) |
| 357 | 357 |
} |
| 358 |
+ |
|
| 359 |
+ // build cert authenticator |
|
| 360 |
+ // TODO: add cert users to etcd? |
|
| 361 |
+ // TODO: provider-qualify cert users? |
|
| 362 |
+ opts := x509request.DefaultVerifyOptions() |
|
| 363 |
+ opts.Roots = roots |
|
| 364 |
+ certauth := x509request.New(opts, x509request.CommonNameUserConversion) |
|
| 365 |
+ authenticators = append(authenticators, group.NewGroupAdder(certauth, []string{authenticatedGroup}))
|
|
| 358 | 366 |
} else {
|
| 359 | 367 |
// No security, use the same client config for all OpenShift clients |
| 360 | 368 |
osClientConfig := kclient.Config{Host: cfg.MasterAddr.URL.String(), Version: latest.Version}
|
| ... | ... |
@@ -362,6 +383,13 @@ func start(cfg *config, args []string) error {
|
| 362 | 362 |
osmaster.DeployerOSClientConfig = osClientConfig |
| 363 | 363 |
} |
| 364 | 364 |
|
| 365 |
+ // TODO: make anonymous auth optional? |
|
| 366 |
+ // TODO: should this map to a real user persisted in etcd? |
|
| 367 |
+ authenticators = append(authenticators, authenticator.RequestFunc(func(req *http.Request) (api.UserInfo, bool, error) {
|
|
| 368 |
+ return &api.DefaultUserInfo{Name: unauthenticatedUsername, Groups: []string{unauthenticatedGroup}}, true, nil
|
|
| 369 |
+ })) |
|
| 370 |
+ osmaster.Authenticator = unionrequest.NewUnionAuthentication(authenticators) |
|
| 371 |
+ |
|
| 365 | 372 |
osmaster.BuildClients() |
| 366 | 373 |
osmaster.EnsureCORSAllowedOrigins(cfg.CORSAllowedOrigins) |
| 367 | 374 |
|
| ... | ... |
@@ -35,7 +35,7 @@ func NewCurrentContextFilter(requestPath string, context Context, handler http.H |
| 35 | 35 |
|
| 36 | 36 |
user, found := context.Get(req) |
| 37 | 37 |
if !found {
|
| 38 |
- http.Error(w, "Need to be authorized to access this method", http.StatusUnauthorized) |
|
| 38 |
+ http.Error(w, "Need to be authenticated to access this method", http.StatusUnauthorized) |
|
| 39 | 39 |
return |
| 40 | 40 |
} |
| 41 | 41 |
|
| ... | ... |
@@ -51,7 +51,7 @@ func InstallThisUser(mux mux, endpoint string, requestsToUsers Context, apiHandl |
| 51 | 51 |
func(w http.ResponseWriter, req *http.Request) {
|
| 52 | 52 |
user, found := requestsToUsers.Get(req) |
| 53 | 53 |
if !found {
|
| 54 |
- http.Error(w, "Need to be authorized to access this method", http.StatusUnauthorized) |
|
| 54 |
+ http.Error(w, "Need to be authenticated to access this method", http.StatusUnauthorized) |
|
| 55 | 55 |
return |
| 56 | 56 |
} |
| 57 | 57 |
|