Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Package frontend implements HTTP server that handles requests to default | 5 // Package frontend implements HTTP server that handles requests to default |
| 6 // module. | 6 // module. |
| 7 package frontend | 7 package frontend |
| 8 | 8 |
| 9 import ( | 9 import ( |
| 10 "database/sql" | 10 "database/sql" |
| 11 "net/http" | 11 "net/http" |
| 12 "strings" | 12 "strings" |
| 13 | 13 |
| 14 "github.com/golang/protobuf/proto" | 14 "github.com/golang/protobuf/proto" |
| 15 | 15 |
| 16 "github.com/julienschmidt/httprouter" | |
| 17 "github.com/luci/gae/service/info" | 16 "github.com/luci/gae/service/info" |
| 18 "github.com/luci/luci-go/appengine/gaeauth/server" | 17 "github.com/luci/luci-go/appengine/gaeauth/server" |
| 19 "github.com/luci/luci-go/appengine/gaemiddleware" | 18 "github.com/luci/luci-go/appengine/gaemiddleware" |
| 20 "github.com/luci/luci-go/common/grpcutil" | 19 "github.com/luci/luci-go/common/grpcutil" |
| 21 "github.com/luci/luci-go/common/logging" | 20 "github.com/luci/luci-go/common/logging" |
| 22 "github.com/luci/luci-go/server/auth" | 21 "github.com/luci/luci-go/server/auth" |
| 23 "github.com/luci/luci-go/server/auth/identity" | 22 "github.com/luci/luci-go/server/auth/identity" |
| 24 "github.com/luci/luci-go/server/discovery" | 23 "github.com/luci/luci-go/server/discovery" |
| 25 "github.com/luci/luci-go/server/middleware" | |
| 26 "github.com/luci/luci-go/server/prpc" | 24 "github.com/luci/luci-go/server/prpc" |
| 25 "github.com/luci/luci-go/server/router" | |
| 27 "github.com/luci/luci-go/server/templates" | 26 "github.com/luci/luci-go/server/templates" |
| 28 "golang.org/x/net/context" | 27 "golang.org/x/net/context" |
| 29 "google.golang.org/appengine" | 28 "google.golang.org/appengine" |
| 30 "google.golang.org/grpc/codes" | 29 "google.golang.org/grpc/codes" |
| 31 | 30 |
| 32 "infra/crimson/proto" // 'crimson' package | 31 "infra/crimson/proto" // 'crimson' package |
| 33 "infra/crimson/server/crimsondb" | 32 "infra/crimson/server/crimsondb" |
| 34 ) | 33 ) |
| 35 | 34 |
| 36 // templateBundle is used to render HTML templates. It provides a base args | 35 // templateBundle is used to render HTML templates. It provides a base args |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 62 "IsAdmin": isAdmin, | 61 "IsAdmin": isAdmin, |
| 63 "User": auth.CurrentUser(c), | 62 "User": auth.CurrentUser(c), |
| 64 "LoginURL": loginURL, | 63 "LoginURL": loginURL, |
| 65 "LogoutURL": logoutURL, | 64 "LogoutURL": logoutURL, |
| 66 }, nil | 65 }, nil |
| 67 }, | 66 }, |
| 68 } | 67 } |
| 69 ) | 68 ) |
| 70 | 69 |
| 71 // Auth middleware. Hard fails when user is not authorized. | 70 // Auth middleware. Hard fails when user is not authorized. |
| 72 func requireAuthWeb(h middleware.Handler) middleware.Handler { | 71 func requireAuthWeb(c *router.Context, next router.Handler) { |
| 73 » return func( | 72 » if auth.CurrentIdentity(c.Context) == identity.AnonymousIdentity { |
| 74 » » c context.Context, | 73 » » loginURL, err := auth.LoginURL(c.Context, "/") |
| 75 » » rw http.ResponseWriter, | 74 » » if err != nil { |
| 76 » » r *http.Request, | 75 » » » logging.Errorf(c.Context, "Failed to get login URL") |
|
Vadim Sh.
2016/06/22 19:50:17
(I know it was like that before, but) return HTTP
nishanths
2016/06/22 20:03:48
Done.
| |
| 77 » » p httprouter.Params) { | 76 » » } |
| 77 » » logging.Infof(c.Context, "Redirecting to %s", loginURL) | |
| 78 » » http.Redirect(c.Writer, c.Request, loginURL, 302) | |
| 79 » » return | |
| 80 » } | |
| 78 | 81 |
| 79 » » if auth.CurrentIdentity(c) == identity.AnonymousIdentity { | 82 » isGoogler, err := auth.IsMember(c.Context, rwGroup) |
| 80 » » » loginURL, err := auth.LoginURL(c, "/") | 83 » if err != nil { |
| 81 » » » if err != nil { | 84 » » c.Writer.WriteHeader(http.StatusInternalServerError) |
| 82 » » » » logging.Errorf(c, "Failed to get login URL") | 85 » » logging.Errorf(c.Context, "Failed to get group membership.") |
| 83 » » » } | 86 » » return |
| 84 » » » logging.Infof(c, "Redirecting to %s", loginURL) | 87 » } |
| 85 » » » http.Redirect(rw, r, loginURL, 302) | 88 » if isGoogler { |
| 86 » » » return | 89 » » next(c) |
| 87 » » } | 90 » » return |
| 91 » } | |
| 88 | 92 |
| 89 » » isGoogler, err := auth.IsMember(c, rwGroup) | 93 » templates.MustRender(c.Context, c.Writer, "pages/access_denied.html", ni l) |
| 90 » » if err != nil { | |
| 91 » » » rw.WriteHeader(http.StatusInternalServerError) | |
| 92 » » » logging.Errorf(c, "Failed to get group membership.") | |
| 93 » » » return | |
| 94 » » } | |
| 95 » » if isGoogler { | |
| 96 » » » h(c, rw, r, p) | |
| 97 » » » return | |
| 98 » » } | |
| 99 | |
| 100 » » templates.MustRender(c, rw, "pages/access_denied.html", nil) | |
| 101 » } | |
| 102 } | 94 } |
| 103 | 95 |
| 104 func addDbToContext(h middleware.Handler) middleware.Handler { | 96 func addDbToContext(c *router.Context, next router.Handler) { |
| 105 » return func( | 97 » c.Context = context.WithValue(c.Context, "dbHandle", dbHandle) |
| 106 » » c context.Context, | 98 » next(c) |
| 107 » » rw http.ResponseWriter, | |
| 108 » » r *http.Request, | |
| 109 » » p httprouter.Params) { | |
| 110 » » c = context.WithValue(c, "dbHandle", dbHandle) | |
| 111 » » h(c, rw, r, p) | |
| 112 » } | |
| 113 } | 99 } |
| 114 | 100 |
| 115 // checkAuthorizationPrpc is a prelude function in the svcdec sense. | 101 // checkAuthorizationPrpc is a prelude function in the svcdec sense. |
| 116 // It hard fails when the user is not authorized. | 102 // It hard fails when the user is not authorized. |
| 117 func checkAuthorizationPrpc( | 103 func checkAuthorizationPrpc( |
| 118 c context.Context, methodName string, req proto.Message) (context.Contex t, error) { | 104 c context.Context, methodName string, req proto.Message) (context.Contex t, error) { |
| 119 | 105 |
| 120 identity := auth.CurrentIdentity(c) | 106 identity := auth.CurrentIdentity(c) |
| 121 logging.Infof(c, "%s", identity) | 107 logging.Infof(c, "%s", identity) |
| 122 hasAccess, err := auth.IsMember(c, rwGroup) | 108 hasAccess, err := auth.IsMember(c, rwGroup) |
| 123 if err != nil { | 109 if err != nil { |
| 124 return nil, grpcutil.Errf(codes.Internal, "%s", err) | 110 return nil, grpcutil.Errf(codes.Internal, "%s", err) |
| 125 } | 111 } |
| 126 if hasAccess { | 112 if hasAccess { |
| 127 return c, nil | 113 return c, nil |
| 128 } | 114 } |
| 129 return nil, grpcutil.Errf(codes.PermissionDenied, | 115 return nil, grpcutil.Errf(codes.PermissionDenied, |
| 130 "%s is not allowed to call APIs", auth.CurrentIdentity(c)) | 116 "%s is not allowed to call APIs", auth.CurrentIdentity(c)) |
| 131 } | 117 } |
| 132 | 118 |
| 133 func base(h middleware.Handler) httprouter.Handle { | 119 func base() router.MiddlewareChain { |
| 134 methods := auth.Authenticator{ | 120 methods := auth.Authenticator{ |
| 135 server.CookieAuth, | 121 server.CookieAuth, |
| 136 } | 122 } |
| 137 » h = auth.Authenticate(h) | 123 » return append( |
| 138 » h = auth.Use(h, methods) | 124 » » gaemiddleware.BaseProd(), |
| 139 » h = templates.WithTemplates(h, templateBundle) | 125 » » templates.WithTemplates(templateBundle), |
| 140 » return gaemiddleware.BaseProd(h) | 126 » » auth.Use(methods), |
| 127 » » auth.Authenticate, | |
| 128 » ) | |
| 141 } | 129 } |
| 142 | 130 |
| 143 // webBase sets up authentication/authorization for http requests. | 131 // webBase sets up authentication/authorization for http requests. |
| 144 func webBase(h middleware.Handler) httprouter.Handle { | 132 func webBase() router.MiddlewareChain { |
| 145 » return base(requireAuthWeb(h)) | 133 » return append(base(), requireAuthWeb) |
| 146 } | 134 } |
| 147 | 135 |
| 148 // prpcBase is the middleware for pRPC API handlers. | 136 // prpcBase returns the middleware for pRPC API handlers. |
| 149 func prpcBase(h middleware.Handler) httprouter.Handle { | 137 func prpcBase() router.MiddlewareChain { |
| 150 // OAuth 2.0 with email scope is registered as a default authenticator | 138 // OAuth 2.0 with email scope is registered as a default authenticator |
| 151 // by importing "github.com/luci/luci-go/appengine/gaeauth/server". | 139 // by importing "github.com/luci/luci-go/appengine/gaeauth/server". |
| 152 // No need to setup an authenticator here. | 140 // No need to setup an authenticator here. |
| 153 // | 141 // |
| 154 // Authorization is checked in checkAuthorizationPrpc using a | 142 // Authorization is checked in checkAuthorizationPrpc using a |
| 155 // service decorator. | 143 // service decorator. |
| 156 » return gaemiddleware.BaseProd(addDbToContext(h)) | 144 » return append(gaemiddleware.BaseProd(), addDbToContext) |
| 157 } | 145 } |
| 158 | 146 |
| 159 //// Routes. | 147 //// Routes. |
| 160 | 148 |
| 161 func init() { | 149 func init() { |
| 162 | 150 |
| 163 // Open DB connection. | 151 // Open DB connection. |
| 164 // Declare 'err' here otherwise the next line shadows the global 'dbHand le' | 152 // Declare 'err' here otherwise the next line shadows the global 'dbHand le' |
| 165 var err error | 153 var err error |
| 166 dbHandle, err = crimsondb.GetDBHandle() | 154 dbHandle, err = crimsondb.GetDBHandle() |
| 167 if err != nil { | 155 if err != nil { |
| 168 logging.Errorf(context.Background(), | 156 logging.Errorf(context.Background(), |
| 169 "Failed to connect to CloudSQL: %v", err) | 157 "Failed to connect to CloudSQL: %v", err) |
| 170 return | 158 return |
| 171 } | 159 } |
| 172 | 160 |
| 173 » router := httprouter.New() | 161 » r := router.New() |
| 174 » gaemiddleware.InstallHandlers(router, base) | 162 » gaemiddleware.InstallHandlers(r, base()) |
| 175 » router.GET("/", webBase(indexPage)) | 163 » r.GET("/", webBase(), indexPage) |
| 176 | 164 |
| 177 var api prpc.Server | 165 var api prpc.Server |
| 178 crimson.RegisterCrimsonServer(&api, &crimson.DecoratedCrimson{ | 166 crimson.RegisterCrimsonServer(&api, &crimson.DecoratedCrimson{ |
| 179 Service: &crimsonService{}, | 167 Service: &crimsonService{}, |
| 180 Prelude: checkAuthorizationPrpc, | 168 Prelude: checkAuthorizationPrpc, |
| 181 }) | 169 }) |
| 182 discovery.Enable(&api) | 170 discovery.Enable(&api) |
| 183 » api.InstallHandlers(router, prpcBase) | 171 » api.InstallHandlers(r, prpcBase()) |
| 184 | 172 |
| 185 » http.DefaultServeMux.Handle("/", router) | 173 » http.DefaultServeMux.Handle("/", r) |
| 186 } | 174 } |
| 187 | 175 |
| 188 //// Handlers. | 176 //// Handlers. |
| 189 | 177 |
| 190 func indexPage( | 178 func indexPage(c *router.Context) { |
| 191 » c context.Context, | 179 » templates.MustRender(c.Context, c.Writer, "pages/index.html", nil) |
| 192 » w http.ResponseWriter, | |
| 193 » r *http.Request, | |
| 194 » p httprouter.Params) { | |
| 195 | |
| 196 » templates.MustRender(c, w, "pages/index.html", nil) | |
| 197 } | 180 } |
| OLD | NEW |