func (smw Session) Handler(ph http.Handler, c context.Context) http.Handler { var abspath string var maxAge, cleanupInterval, cleanupMaxAge time.Duration if filepath.IsAbs(smw.Path) { abspath = smw.Path } else { var err error abspath, err = filepath.Abs(path.Join(filepath.Dir(os.Args[0]), smw.Path)) if err != nil { panic(err) } } if smw.MaxAge != "" { var err error maxAge, err = time.ParseDuration(smw.MaxAge) if err != nil { panic(err) } } logger := webfw.GetLogger(c) if smw.CleanupInterval != "" { var err error cleanupInterval, err = time.ParseDuration(smw.CleanupInterval) if err != nil { panic(err) } cleanupMaxAge, err = time.ParseDuration(smw.CleanupMaxAge) if err != nil { panic(err) } go func() { for _ = range time.Tick(cleanupInterval) { logger.Print("Cleaning up old sessions") if err := context.CleanupSessions(abspath, cleanupMaxAge); err != nil { logger.Printf("Failed to clean up sessions: %v", err) } } }() } handler := func(w http.ResponseWriter, r *http.Request) { uriParts := strings.SplitN(r.RequestURI, "?", 2) if uriParts[0] == "" { uriParts[0] = r.URL.Path } ignore := false for _, prefix := range smw.IgnoreURLPrefix { if prefix[0] == '/' { prefix = prefix[1:] } if strings.HasPrefix(uriParts[0], smw.Pattern+prefix+"/") { ignore = true break } if uriParts[0] == smw.Pattern+prefix { ignore = true break } } if ignore { ph.ServeHTTP(w, r) return } firstTimer := false var sess context.Session if smw.SessionGenerator == nil { sess = context.NewSession(smw.Secret, smw.Cipher, abspath) } else { sess = smw.SessionGenerator(smw.Secret, smw.Cipher, abspath) } sess.SetMaxAge(maxAge) err := sess.Read(r, c) if err != nil && err != context.ErrExpired && err != context.ErrNotExist { sess.SetName(util.UUID()) firstTimer = true if err != context.ErrCookieNotExist { logger.Printf("Error reading session: %v", err) } } c.Set(r, context.BaseCtxKey("session"), sess) c.Set(r, context.BaseCtxKey("firstTimer"), firstTimer) rec := util.NewRecorderHijacker(w) ph.ServeHTTP(rec, r) for k, v := range rec.Header() { w.Header()[k] = v } if sess != nil { if err := sess.Write(w); err != nil { logger.Printf("Unable to write session: %v", err) } } w.WriteHeader(rec.GetCode()) w.Write(rec.GetBody().Bytes()) } return http.HandlerFunc(handler) }
func (mw Auth) Handler(ph http.Handler, c context.Context, l *log.Logger) http.Handler { handler := func(w http.ResponseWriter, r *http.Request) { for _, prefix := range mw.IgnoreURLPrefix { if prefix[0] == '/' { prefix = prefix[1:] } if strings.HasPrefix(r.URL.Path, mw.Pattern+prefix+"/") { ph.ServeHTTP(w, r) return } } route, _, ok := webfw.GetDispatcher(c).RequestRoute(r) if !ok { ph.ServeHTTP(w, r) return } switch ac := route.Controller.(type) { case AuthController: if !ac.LoginRequired(c, r) { ph.ServeHTTP(w, r) return } sess := webfw.GetSession(c, r) var u User validUser := false if uv, ok := sess.Get(authkey); ok { if u, ok = uv.(User); ok { validUser = true } } if !validUser { if uv, ok := sess.Get(namekey); ok { if n, ok := uv.(string); ok { var err error u, err = mw.DB.GetUser(n) if err == nil { validUser = true sess.Set(authkey, u) } else if _, ok := err.(ValidationError); !ok { l.Print(err) } } } } if validUser && !u.Active { Debug.Println("User " + u.Login + " is inactive") validUser = false } if !validUser { d := webfw.GetDispatcher(c) sess.SetFlash(CtxKey("return-to"), r.URL.Path) path := d.NameToPath("auth-login", webfw.MethodGet) if path == "" { path = "/" } http.Redirect(w, r, path, http.StatusMovedPermanently) return } case ApiAuthController: if !ac.AuthRequired(c, r) { ph.ServeHTTP(w, r) return } var u User var err error auth := r.Header.Get("Authorization") validUser := false if auth != "" { switch { default: if !strings.HasPrefix(auth, "Readeef ") { break } auth = auth[len("Readeef "):] parts := strings.SplitN(auth, ":", 2) login := parts[0] u, err = mw.DB.GetUser(login) if err != nil { l.Printf("Error getting db user '%s': %v\n", login, err) break } var decoded []byte decoded, err = base64.StdEncoding.DecodeString(parts[1]) if err != nil { l.Printf("Error decoding auth header: %v\n", err) break } date := r.Header.Get("X-Date") t, err := time.Parse(http.TimeFormat, date) if err != nil || t.Add(30*time.Second).Before(time.Now()) { break } nonce := r.Header.Get("X-Nonce") if !mw.Nonce.Check(nonce) { break } mw.Nonce.Remove(nonce) buf := util.BufferPool.GetBuffer() defer util.BufferPool.Put(buf) buf.ReadFrom(r.Body) r.Body = ioutil.NopCloser(buf) bodyHash := md5.New() if _, err := bodyHash.Write(buf.Bytes()); err != nil { l.Printf("Error generating the hash for the request body: %v\n", err) break } contentMD5 := base64.StdEncoding.EncodeToString(bodyHash.Sum(nil)) message := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n", r.RequestURI, r.Method, contentMD5, r.Header.Get("Content-Type"), date, nonce) b := make([]byte, base64.StdEncoding.EncodedLen(len(u.MD5API))) base64.StdEncoding.Encode(b, u.MD5API) hm := hmac.New(sha256.New, b) if _, err := hm.Write([]byte(message)); err != nil { l.Printf("Error generating the hashed message: %v\n", err) break } if !hmac.Equal(hm.Sum(nil), decoded) { l.Printf("Error matching the supplied auth message to the generated one.\n") break } if !u.Active { Debug.Println("User " + u.Login + " is inactive") break } validUser = true } } if !validUser { w.WriteHeader(http.StatusForbidden) return } c.Set(r, context.BaseCtxKey("user"), u) } ph.ServeHTTP(w, r) } return http.HandlerFunc(handler) }
func (imw I18N) Handler(ph http.Handler, c context.Context) http.Handler { for _, l := range imw.Languages { file, err := fs.DefaultFS.OpenRoot(imw.Dir, l+".all.json") if err == nil { var b []byte if b, err = ioutil.ReadAll(file); err == nil { err = i18n.ParseTranslationFileBytes(l+".all.json", b) } } if err != nil { panic(fmt.Sprintf("Error opening locale file '%s.all.json': %v\n", l, err)) } } renderer := webfw.GetRenderer(c) renderer.Funcs(imw.TemplateFuncMap()) handler := func(w http.ResponseWriter, r *http.Request) { c.Set(r, context.BaseCtxKey("langs"), imw.Languages) if len(imw.Languages) == 0 { c.Set(r, context.BaseCtxKey("lang"), "") ph.ServeHTTP(w, r) return } found := false uriParts := strings.SplitN(r.RequestURI, "?", 2) if uriParts[0] == "" { uriParts[0] = r.URL.Path } for _, prefix := range imw.IgnoreURLPrefix { if prefix[0] == '/' { prefix = prefix[1:] } if strings.HasPrefix(uriParts[0], imw.Pattern+prefix+"/") { found = true break } if uriParts[0] == imw.Pattern+prefix { found = true break } } if !found { for _, language := range imw.Languages { if uriParts[0] == imw.Pattern+language { url := uriParts[0] + "/" if len(uriParts) > 1 && uriParts[1] != "" { url += "?" + uriParts[1] } http.Redirect(w, r, url, http.StatusFound) return } if strings.HasPrefix(uriParts[0], imw.Pattern+language+"/") { r.URL.Path = imw.Pattern + r.URL.Path[len(imw.Pattern+language+"/"):] uriParts[0] = imw.Pattern + uriParts[0][len(imw.Pattern+language+"/"):] r.RequestURI = strings.Join(uriParts, "?") c.Set(r, context.BaseCtxKey("lang"), language) found = true s := webfw.GetSession(c, r) s.Set("language", language) break } } } if !found { fallback := webfw.GetFallbackLanguage(c, r, imw.FallbackLanguage) index := strings.Index(fallback, "-") short := fallback if index > -1 { short = fallback[:index] } foundShort := false for _, language := range imw.Languages { if language == fallback { found = true break } if language == short { foundShort = true } } var language string if found { language = fallback } else if foundShort { language = short } else { language = imw.FallbackLanguage } url := imw.Pattern + language + uriParts[0][len(imw.Pattern)-1:] if len(uriParts) > 1 && uriParts[1] != "" { url += "?" + uriParts[1] } http.Redirect(w, r, url, http.StatusFound) return } ph.ServeHTTP(w, r) } return http.HandlerFunc(handler) }
func (con WebSocket) AuthReject(c context.Context, r *http.Request) { c.Set(r, readeef.CtxKey("forbidden"), true) }
func (mw Auth) Handler(ph http.Handler, c context.Context) http.Handler { logger := webfw.GetLogger(c) handler := func(w http.ResponseWriter, r *http.Request) { for _, prefix := range mw.IgnoreURLPrefix { if prefix[0] == '/' { prefix = prefix[1:] } if strings.HasPrefix(r.URL.Path, mw.Pattern+prefix+"/") { ph.ServeHTTP(w, r) return } } route, _, ok := webfw.GetDispatcher(c).RequestRoute(r) if !ok { ph.ServeHTTP(w, r) return } repo := GetRepo(c) switch ac := route.Controller.(type) { case AuthController: if !ac.LoginRequired(c, r) { ph.ServeHTTP(w, r) return } sess := webfw.GetSession(c, r) var u content.User validUser := false if uv, ok := sess.Get(AuthUserKey); ok { if u, ok = uv.(content.User); ok { validUser = true } } if !validUser { if uv, ok := sess.Get(AuthNameKey); ok { if n, ok := uv.(data.Login); ok { u = repo.UserByLogin(n) if u.HasErr() { logger.Print(u.Err()) } else { validUser = true sess.Set(AuthUserKey, u) } } } } if validUser && !u.Data().Active { logger.Infoln("User " + u.Data().Login + " is inactive") validUser = false } if !validUser { d := webfw.GetDispatcher(c) sess.SetFlash(CtxKey("return-to"), r.URL.Path) path := d.NameToPath("auth-login", webfw.MethodGet) if path == "" { path = "/" } http.Redirect(w, r, path, http.StatusMovedPermanently) return } case ApiAuthController: if !ac.AuthRequired(c, r) { ph.ServeHTTP(w, r) return } url, login, signature, nonce, date, t := authData(r) validUser := false var u content.User if login != "" && signature != "" && !t.IsZero() { switch { default: u = repo.UserByLogin(data.Login(login)) if u.HasErr() { logger.Printf("Error getting db user '%s': %v\n", login, u.Err()) break } decoded, err := base64.StdEncoding.DecodeString(signature) if err != nil { logger.Printf("Error decoding auth header: %v\n", err) break } if t.Add(30 * time.Second).Before(time.Now()) { break } if !mw.Nonce.Check(nonce) { break } mw.Nonce.Remove(nonce) buf := util.BufferPool.GetBuffer() defer util.BufferPool.Put(buf) buf.ReadFrom(r.Body) r.Body = ioutil.NopCloser(buf) bodyHash := md5.New() if _, err := bodyHash.Write(buf.Bytes()); err != nil { logger.Printf("Error generating the hash for the request body: %v\n", err) break } contentMD5 := base64.StdEncoding.EncodeToString(bodyHash.Sum(nil)) message := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s\n", url, r.Method, contentMD5, r.Header.Get("Content-Type"), date, nonce) b := make([]byte, base64.StdEncoding.EncodedLen(len(u.Data().MD5API))) base64.StdEncoding.Encode(b, u.Data().MD5API) hm := hmac.New(sha256.New, b) if _, err := hm.Write([]byte(message)); err != nil { logger.Printf("Error generating the hashed message: %v\n", err) break } if !hmac.Equal(hm.Sum(nil), decoded) { logger.Printf("Error matching the supplied auth message to the generated one.\n") break } if !u.Data().Active { logger.Println("User " + u.Data().Login + " is inactive") break } validUser = true } } if validUser { c.Set(r, context.BaseCtxKey("user"), u) } else { if rej, ok := ac.(AuthRejectHandler); ok { rej.AuthReject(c, r) } else { w.WriteHeader(http.StatusUnauthorized) return } } } ph.ServeHTTP(w, r) } return http.HandlerFunc(handler) }