Browse code

Enable authentication, add x509 cert auth, anonymous auth

Add system:authenticated group

Jordan Liggitt authored on 2015/01/22 03:20:55
Showing 9 changed files
... ...
@@ -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