extract all auth related deps into Authenticator obj

This commit is contained in:
Umputun
2018-02-15 23:40:12 -06:00
parent 776c9250b0
commit ed52c4a590
8 changed files with 55 additions and 44 deletions
+12 -10
View File
@@ -107,16 +107,18 @@ func main() {
}
srv := rest.Server{
Version: revision,
DataService: dataService,
SessionStore: sessionStore,
Admins: opts.Admins,
DevMode: opts.DevMode,
Exporter: &exporter,
AuthProviders: makeAuthProviders(sessionStore, avatarProxy),
Cache: common.NewLoadingCache(4*time.Hour, 15*time.Minute, postFlushFn),
AvatarProxy: avatarProxy,
Notifier: notifier.NewNoperation(),
Version: revision,
DataService: dataService,
DevMode: opts.DevMode,
Exporter: &exporter,
Authenticator: auth.Authenticator{
Admins: opts.Admins,
SessionStore: sessionStore,
Providers: makeAuthProviders(sessionStore, avatarProxy),
AvatarProxy: avatarProxy,
},
Cache: common.NewLoadingCache(4*time.Hour, 15*time.Minute, postFlushFn),
Notifier: notifier.NewNoperation(),
}
if opts.DevMode {
+2 -3
View File
@@ -12,7 +12,6 @@ import (
"github.com/go-chi/render"
"github.com/umputun/remark/app/migrator"
"github.com/umputun/remark/app/rest/auth"
"github.com/umputun/remark/app/rest/common"
"github.com/umputun/remark/app/store"
)
@@ -25,9 +24,9 @@ type admin struct {
cache common.LoadingCache
}
func (a *admin) routes() chi.Router {
func (a *admin) routes(middlewares ...func(http.Handler) http.Handler) chi.Router {
router := chi.NewRouter()
router.Use(auth.AdminOnly)
router.Use(middlewares...)
router.Delete("/comment/{id}", a.deleteCommentCtrl)
router.Put("/user/{userid}", a.setBlockCtrl)
router.Get("/export", a.exportCtrl)
+13 -4
View File
@@ -6,6 +6,7 @@ import (
"github.com/gorilla/sessions"
"github.com/umputun/remark/app/rest/avatar"
"github.com/umputun/remark/app/rest/common"
"github.com/umputun/remark/app/store"
)
@@ -28,8 +29,16 @@ var devUser = store.User{
Admin: true,
}
// Authenticator is top level auth object providing middlewares
type Authenticator struct {
SessionStore sessions.Store
AvatarProxy *avatar.Proxy
Admins []string
Providers []Provider
}
// Auth middleware adds auth from session and populates user info
func Auth(sessionStore sessions.Store, admins []string, modes []Mode) func(http.Handler) http.Handler {
func (a *Authenticator) Auth(modes []Mode) func(http.Handler) http.Handler {
inModes := func(mode Mode) bool {
for _, m := range modes {
@@ -53,7 +62,7 @@ func Auth(sessionStore sessions.Store, admins []string, modes []Mode) func(http.
return
}
session, err := sessionStore.Get(r, "remark")
session, err := a.SessionStore.Get(r, "remark")
if err != nil && inModes(Full) { // in full auth lack of session causes Unauthorized
http.Error(w, err.Error(), http.StatusUnauthorized)
return
@@ -72,7 +81,7 @@ func Auth(sessionStore sessions.Store, admins []string, modes []Mode) func(http.
if ok { // if uinfo in session, populate to context
user := uinfoData.(store.User)
for _, admin := range admins {
for _, admin := range a.Admins {
if admin == user.ID {
user.Admin = true
break
@@ -91,7 +100,7 @@ func Auth(sessionStore sessions.Store, admins []string, modes []Mode) func(http.
}
// AdminOnly allows access to admins
func AdminOnly(next http.Handler) http.Handler {
func (a *Authenticator) AdminOnly(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
user, err := common.GetUserInfo(r)
+2 -2
View File
@@ -83,7 +83,7 @@ func (p *Proxy) Put(u store.User) (avatarURL string, err error) {
}
// Routes returns auth routes for given provider
func (p *Proxy) Routes() chi.Router {
func (p *Proxy) Routes() (string, chi.Router) {
router := chi.NewRouter()
// GET /123456789.image
@@ -118,7 +118,7 @@ func (p *Proxy) Routes() chi.Router {
}
})
return router
return p.RoutePath, router
}
// encodeID hashes user id to sha1
+4 -2
View File
@@ -66,7 +66,8 @@ func TestRoutes(t *testing.T) {
}
rr := httptest.NewRecorder()
handler := http.Handler(p.Routes())
_, routes := p.Routes()
handler := http.Handler(routes)
handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
@@ -92,7 +93,8 @@ func TestRoutesDefault(t *testing.T) {
}
rr := httptest.NewRecorder()
handler := http.Handler(p.Routes())
_, routes := p.Routes()
handler := http.Handler(routes)
handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
+6 -2
View File
@@ -141,9 +141,13 @@ func Logger(flags ...LoggerFlag) func(http.Handler) http.Handler {
q = qun
}
remoteIP := strings.Split(r.RemoteAddr, ":")[0]
if strings.HasPrefix(r.RemoteAddr, "[") {
remoteIP = strings.Split(r.RemoteAddr, "]:")[0] + "]"
}
log.Printf("[INFO] REST %s - %s - %s - %d (%d) - %v %s %s",
r.Method, q, strings.Split(r.RemoteAddr, ":")[0],
ww.Status(), ww.BytesWritten(), t2.Sub(t1), user, body)
r.Method, q, remoteIP, ww.Status(), ww.BytesWritten(), t2.Sub(t1), user, body)
}()
h.ServeHTTP(ww, r)
+15 -20
View File
@@ -17,14 +17,12 @@ import (
"github.com/go-chi/chi/middleware"
"github.com/go-chi/render"
"github.com/gorilla/context"
"github.com/gorilla/sessions"
"github.com/pkg/errors"
"gopkg.in/russross/blackfriday.v2"
"github.com/umputun/remark/app/migrator"
"github.com/umputun/remark/app/notifier"
"github.com/umputun/remark/app/rest/auth"
"github.com/umputun/remark/app/rest/avatar"
"github.com/umputun/remark/app/rest/common"
"github.com/umputun/remark/app/rest/format"
"github.com/umputun/remark/app/store"
@@ -32,18 +30,15 @@ import (
// Server is a rest access server
type Server struct {
Version string
Version string
DevMode bool
DataService store.Service
Admins []string
AuthProviders []auth.Provider
SessionStore sessions.Store
Authenticator auth.Authenticator
Exporter migrator.Exporter
Cache common.LoadingCache
AvatarProxy *avatar.Proxy
Notifier notifier.Interface
DevMode bool
httpServer *http.Server
mod admin
}
@@ -61,8 +56,8 @@ func (s *Server) Run(port int) {
return modes
}
if len(s.Admins) > 0 {
log.Printf("[DEBUG] admins %+v", s.Admins)
if len(s.Authenticator.Admins) > 0 {
log.Printf("[DEBUG] admins %+v", s.Authenticator.Admins)
}
router := chi.NewRouter()
@@ -71,23 +66,23 @@ func (s *Server) Run(port int) {
router.Use(tollbooth_chi.LimitHandler(tollbooth.NewLimiter(10, nil)))
// all request by default allow anonymous access
router.Use(auth.Auth(s.SessionStore, s.Admins, maybeWithDevMode(auth.Anonymous)))
router.Use(s.Authenticator.Auth(maybeWithDevMode(auth.Anonymous)))
router.Use(AppInfo("remark42", s.Version), Ping, Logger(LogAll))
router.Use(context.ClearHandler) // if you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler
// auth routes for all providers
router.Route("/auth", func(r chi.Router) {
for _, provider := range s.AuthProviders {
for _, provider := range s.Authenticator.Providers {
r.Mount("/"+provider.Name, provider.Routes()) // mount auth providers as /auth/{name}
}
if len(s.AuthProviders) > 0 {
if len(s.Authenticator.Providers) > 0 {
// shortcut, can be any of providers, all logouts do the same - removes cookie
r.Get("/logout", s.AuthProviders[0].LogoutHandler)
r.Get("/logout", s.Authenticator.Providers[0].LogoutHandler)
}
})
router.Mount(s.AvatarProxy.RoutePath, s.AvatarProxy.Routes())
router.Mount(s.Authenticator.AvatarProxy.Routes())
// api routes
router.Route("/api/v1", func(rapi chi.Router) {
@@ -102,7 +97,7 @@ func (s *Server) Run(port int) {
rapi.Get("/config", s.configCtrl)
// protected routes, require auth
rapi.With(auth.Auth(s.SessionStore, s.Admins, maybeWithDevMode(auth.Full))).Group(func(rauth chi.Router) {
rapi.With(s.Authenticator.Auth(maybeWithDevMode(auth.Full))).Group(func(rauth chi.Router) {
rauth.Post("/comment", s.createCommentCtrl)
rauth.Put("/comment/{id}", s.updateCommentCtrl)
rauth.Get("/user", s.userInfoCtrl)
@@ -111,7 +106,7 @@ func (s *Server) Run(port int) {
rauth.Get("/notify", s.notifyStatusCtrl)
// admin routes, admin users only
s.mod = admin{dataService: s.DataService, exporter: s.Exporter, cache: s.Cache}
rauth.Mount("/admin", s.mod.routes())
rauth.Mount("/admin", s.mod.routes(s.Authenticator.AdminOnly))
})
})
@@ -343,10 +338,10 @@ func (s *Server) configCtrl(w http.ResponseWriter, r *http.Request) {
cnf := config{
Version: s.Version,
EditDuration: int(s.DataService.EditDuration.Seconds()),
Admins: s.Admins,
Admins: s.Authenticator.Admins,
}
authNames := []string{}
for _, ap := range s.AuthProviders {
for _, ap := range s.Authenticator.Providers {
authNames = append(authNames, ap.Name)
}
cnf.Auth = authNames
+1 -1
View File
@@ -9,7 +9,7 @@ GET {{host}}/api/v1/find?site=remark&sort=time&format=plain&url=https://radio-t.
GET {{host}}/api/v1/last/50?site=remark
### create comment
POST 127.0.0.1:8080/api/v1/comment
POST {{host}}/api/v1/comment
Content-Type: application/json
{