extract all auth related deps into Authenticator obj
This commit is contained in:
+12
-10
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user