Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: server/auth/context.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Update tests Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package auth 5 package auth
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "net/http" 9 "net/http"
10 10
11 "github.com/julienschmidt/httprouter"
12 "golang.org/x/net/context" 11 "golang.org/x/net/context"
13 12
14 "github.com/luci/luci-go/common/errors" 13 "github.com/luci/luci-go/common/errors"
15 "github.com/luci/luci-go/common/logging" 14 "github.com/luci/luci-go/common/logging"
16 15
17 "github.com/luci/luci-go/server/auth/identity" 16 "github.com/luci/luci-go/server/auth/identity"
18 » "github.com/luci/luci-go/server/middleware" 17 » "github.com/luci/luci-go/server/router"
19 ) 18 )
20 19
21 type authenticatorKey int 20 type authenticatorKey int
22 21
23 // SetAuthenticator injects copy of Authenticator (list of auth methods) into 22 // SetAuthenticator injects copy of Authenticator (list of auth methods) into
24 // the context to use by default in LoginURL, LogoutURL and Authenticate. 23 // the context to use by default in LoginURL, LogoutURL and Authenticate.
25 // Usually installed into the context by some base middleware. 24 // Usually installed into the context by some base middleware.
26 func SetAuthenticator(c context.Context, a Authenticator) context.Context { 25 func SetAuthenticator(c context.Context, a Authenticator) context.Context {
27 return context.WithValue(c, authenticatorKey(0), append(Authenticator(ni l), a...)) 26 return context.WithValue(c, authenticatorKey(0), append(Authenticator(ni l), a...))
28 } 27 }
29 28
30 // GetAuthenticator extracts instance of Authenticator (list of auth methods) 29 // GetAuthenticator extracts instance of Authenticator (list of auth methods)
31 // from the context. Returns nil if no authenticator is set. 30 // from the context. Returns nil if no authenticator is set.
32 func GetAuthenticator(c context.Context) Authenticator { 31 func GetAuthenticator(c context.Context) Authenticator {
33 if a, ok := c.Value(authenticatorKey(0)).(Authenticator); ok { 32 if a, ok := c.Value(authenticatorKey(0)).(Authenticator); ok {
34 return a 33 return a
35 } 34 }
36 return nil 35 return nil
37 } 36 }
38 37
39 // Use is a middleware that simply puts given Authenticator into the context. 38 // Use is a middleware that simply puts given Authenticator into the context.
40 func Use(h middleware.Handler, a Authenticator) middleware.Handler { 39 func Use(a Authenticator) router.Handler {
41 » return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { 40 » return func(c *router.Context) {
42 » » h(SetAuthenticator(c, a), rw, r, p) 41 » » c.Context = SetAuthenticator(c.Context, a)
43 } 42 }
44 } 43 }
45 44
46 // LoginURL returns a URL that, when visited, prompts the user to sign in, 45 // LoginURL returns a URL that, when visited, prompts the user to sign in,
47 // then redirects the user to the URL specified by dest. It is wrapper around 46 // then redirects the user to the URL specified by dest. It is wrapper around
48 // LoginURL method of Authenticator in the context. 47 // LoginURL method of Authenticator in the context.
49 func LoginURL(c context.Context, dest string) (string, error) { 48 func LoginURL(c context.Context, dest string) (string, error) {
50 return GetAuthenticator(c).LoginURL(c, dest) 49 return GetAuthenticator(c).LoginURL(c, dest)
51 } 50 }
52 51
53 // LogoutURL returns a URL that, when visited, signs the user out, 52 // LogoutURL returns a URL that, when visited, signs the user out,
54 // then redirects the user to the URL specified by dest. It is wrapper around 53 // then redirects the user to the URL specified by dest. It is wrapper around
55 // LogoutURL method of Authenticator in the context. 54 // LogoutURL method of Authenticator in the context.
56 func LogoutURL(c context.Context, dest string) (string, error) { 55 func LogoutURL(c context.Context, dest string) (string, error) {
57 return GetAuthenticator(c).LogoutURL(c, dest) 56 return GetAuthenticator(c).LogoutURL(c, dest)
58 } 57 }
59 58
60 // Authenticate returns a wrapper around middleware.Handler that performs 59 // Authenticate returns a wrapper around middleware.Handler that performs
61 // authentication (using Authenticator in the context) and calls `h`. 60 // authentication (using Authenticator in the context) and calls `h`.
62 func Authenticate(h middleware.Handler) middleware.Handler { 61 func Authenticate() router.Handler {
63 » return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { 62 » return func(c *router.Context) {
64 » » a := GetAuthenticator(c) 63 » » a := GetAuthenticator(c.Context)
65 if a == nil { 64 if a == nil {
66 » » » replyError(c, rw, 500, "Authentication middleware is not configured") 65 » » » replyError(c.Context, c.Writer, 500, "Authentication mid dleware is not configured")
66 » » » c.Abort()
67 return 67 return
68 } 68 }
69 » » ctx, err := a.Authenticate(c, r) 69 » » ctx, err := a.Authenticate(c.Context, c.Request)
70 switch { 70 switch {
71 case errors.IsTransient(err): 71 case errors.IsTransient(err):
72 » » » replyError(c, rw, 500, fmt.Sprintf("Transient error duri ng authentication - %s", err)) 72 » » » replyError(c.Context, c.Writer, 500, fmt.Sprintf("Transi ent error during authentication - %s", err))
73 » » » c.Abort()
73 case err != nil: 74 case err != nil:
74 » » » replyError(c, rw, 401, fmt.Sprintf("Authentication error - %s", err)) 75 » » » replyError(c.Context, c.Writer, 401, fmt.Sprintf("Authen tication error - %s", err))
76 » » » c.Abort()
75 default: 77 default:
76 » » » h(ctx, rw, r, p) 78 » » » c.Context = ctx
77 } 79 }
78 } 80 }
79 } 81 }
80 82
81 // Autologin is a middleware that redirects the user to login page if the user 83 // Autologin is a middleware that redirects the user to login page if the user
82 // is not signed in yet or authentication methods do not recognize user 84 // is not signed in yet or authentication methods do not recognize user
83 // credentials. Uses Authenticator instance in the context. 85 // credentials. Uses Authenticator instance in the context.
84 func Autologin(h middleware.Handler) middleware.Handler { 86 func Autologin() router.Handler {
85 » return func(c context.Context, rw http.ResponseWriter, r *http.Request, p httprouter.Params) { 87 » return func(c *router.Context) {
86 » » a := GetAuthenticator(c) 88 » » a := GetAuthenticator(c.Context)
87 if a == nil { 89 if a == nil {
88 » » » replyError(c, rw, 500, "Authentication middleware is not configured") 90 » » » replyError(c.Context, c.Writer, 500, "Authentication mid dleware is not configured")
91 » » » c.Abort()
89 return 92 return
90 } 93 }
91 » » ctx, err := a.Authenticate(c, r) 94 » » ctx, err := a.Authenticate(c.Context, c.Request)
92 95
93 switch { 96 switch {
94 case errors.IsTransient(err): 97 case errors.IsTransient(err):
95 » » » replyError(c, rw, 500, fmt.Sprintf("Transient error duri ng authentication - %s", err)) 98 » » » replyError(c.Context, c.Writer, 500, fmt.Sprintf("Transi ent error during authentication - %s", err))
99 » » » c.Abort()
96 100
97 case err != nil: 101 case err != nil:
98 » » » replyError(c, rw, 401, fmt.Sprintf("Authentication error - %s", err)) 102 » » » replyError(c.Context, c.Writer, 401, fmt.Sprintf("Authen tication error - %s", err))
103 » » » c.Abort()
99 104
100 case CurrentIdentity(ctx).Kind() == identity.Anonymous: 105 case CurrentIdentity(ctx).Kind() == identity.Anonymous:
101 » » » dest := r.RequestURI 106 » » » dest := c.Request.RequestURI
102 if dest == "" { 107 if dest == "" {
103 // Make r.URL relative. 108 // Make r.URL relative.
104 » » » » destURL := *r.URL 109 » » » » destURL := *c.Request.URL
105 destURL.Host = "" 110 destURL.Host = ""
106 destURL.Scheme = "" 111 destURL.Scheme = ""
107 dest = destURL.String() 112 dest = destURL.String()
108 } 113 }
109 » » » url, err := a.LoginURL(c, dest) 114 » » » url, err := a.LoginURL(c.Context, dest)
110 if err != nil { 115 if err != nil {
111 if errors.IsTransient(err) { 116 if errors.IsTransient(err) {
112 » » » » » replyError(c, rw, 500, fmt.Sprintf("Tran sient error during authentication - %s", err)) 117 » » » » » replyError(c.Context, c.Writer, 500, fmt .Sprintf("Transient error during authentication - %s", err))
113 } else { 118 } else {
114 » » » » » replyError(c, rw, 401, fmt.Sprintf("Auth entication error - %s", err)) 119 » » » » » replyError(c.Context, c.Writer, 401, fmt .Sprintf("Authentication error - %s", err))
115 } 120 }
121 c.Abort()
116 return 122 return
117 } 123 }
118 » » » http.Redirect(rw, r, url, 302) 124 » » » http.Redirect(c.Writer, c.Request, url, 302)
119 125
120 default: 126 default:
121 » » » h(ctx, rw, r, p) 127 » » » c.Context = ctx
122 } 128 }
123 } 129 }
124 } 130 }
125 131
126 // replyError logs the error and writes it to ResponseWriter. 132 // replyError logs the error and writes it to ResponseWriter.
127 func replyError(c context.Context, rw http.ResponseWriter, code int, msg string) { 133 func replyError(c context.Context, rw http.ResponseWriter, code int, msg string) {
128 logging.Errorf(c, "HTTP %d: %s", code, msg) 134 logging.Errorf(c, "HTTP %d: %s", code, msg)
129 http.Error(rw, msg, code) 135 http.Error(rw, msg, code)
130 } 136 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698