123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- package login
- import (
- "context"
- "log"
- "net/http"
- "regexp"
- "strings"
- "time"
- )
- type ContextUserKey int
- const (
- UserKey ContextUserKey = iota
- loginWIPKey
- )
- var staticFileRe = regexp.MustCompile(`\.(css|js|gif|jpg|jpeg|png|ico|svg|ttf|eot|woff|woff2)$`)
- func Authenticate(b *Builder) func(next http.Handler) http.Handler {
- return func(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if staticFileRe.MatchString(strings.ToLower(r.URL.Path)) {
- next.ServeHTTP(w, r)
- return
- }
- if _, ok := b.allowURLs[r.URL.Path]; ok {
- next.ServeHTTP(w, r)
- return
- }
- path := strings.TrimRight(r.URL.Path, "/")
- claims, err := parseUserClaimsFromCookie(r, b.authCookieName, b.secret)
- if err != nil {
- log.Println(err)
- b.setContinueURL(w, r)
- if path == b.loginPageURL {
- next.ServeHTTP(w, r)
- } else {
- http.Redirect(w, r, b.loginPageURL, http.StatusFound)
- }
- return
- }
- var user interface{}
- var secureSalt string
- if b.userModel != nil {
- var err error
- user, err = b.findUserByID(claims.UserID)
- if err == nil {
- if claims.Provider == "" {
- if user.(UserPasser).GetPasswordUpdatedAt() != claims.PassUpdatedAt {
- err = ErrUserPassChanged
- }
- if user.(UserPasser).GetLocked() {
- err = ErrUserLocked
- }
- } else {
- user.(OAuthUser).SetAvatar(claims.AvatarURL)
- }
- }
- if err != nil {
- log.Println(err)
- switch err {
- case ErrUserNotFound:
- setFailCodeFlash(w, FailCodeUserNotFound)
- case ErrUserLocked:
- setFailCodeFlash(w, FailCodeUserLocked)
- case ErrUserPassChanged:
- setWarnCodeFlash(w, WarnCodePasswordHasBeenChanged)
- default:
- setFailCodeFlash(w, FailCodeSystemError)
- }
- if path == b.LogoutURL {
- next.ServeHTTP(w, r)
- } else {
- http.Redirect(w, r, b.LogoutURL, http.StatusFound)
- }
- return
- }
- if b.sessionSecureEnabled {
- secureSalt = user.(SessionSecurer).GetSecure()
- _, err := parseBaseClaimsFromCookie(r, b.authSecureCookieName, b.secret+secureSalt)
- if err != nil {
- if path == b.LogoutURL {
- next.ServeHTTP(w, r)
- } else {
- http.Redirect(w, r, b.LogoutURL, http.StatusFound)
- }
- return
- }
- }
- } else {
- user = claims
- }
- if b.autoExtendSession && time.Now().Sub(claims.IssuedAt.Time).Seconds() > float64(b.sessionMaxAge)/10 {
- oldSessionToken := b.mustGetSessionToken(*claims)
- claims.RegisteredClaims = b.genBaseSessionClaim(claims.UserID)
- if err := b.setAuthCookiesFromUserClaims(w, claims, secureSalt); err != nil {
- setFailCodeFlash(w, FailCodeSystemError)
- if path == b.LogoutURL {
- next.ServeHTTP(w, r)
- } else {
- http.Redirect(w, r, b.LogoutURL, http.StatusFound)
- }
- return
- }
- if b.afterExtendSessionHook != nil {
- setCookieForRequest(r, &http.Cookie{Name: b.authCookieName, Value: b.mustGetSessionToken(*claims)})
- if herr := b.afterExtendSessionHook(r, user, oldSessionToken); herr != nil {
- setFailCodeFlash(w, FailCodeSystemError)
- http.Redirect(w, r, b.LogoutURL, http.StatusFound)
- return
- }
- }
- }
- r = r.WithContext(context.WithValue(r.Context(), UserKey, user))
- if path == b.LogoutURL {
- next.ServeHTTP(w, r)
- return
- }
- if claims.Provider == "" && b.totpEnabled {
- if !user.(UserPasser).GetIsTOTPSetup() {
- if path == b.loginPageURL {
- next.ServeHTTP(w, r)
- return
- }
- r = r.WithContext(context.WithValue(r.Context(), loginWIPKey, true))
- if path == b.totpSetupPageURL {
- next.ServeHTTP(w, r)
- return
- }
- http.Redirect(w, r, b.totpSetupPageURL, http.StatusFound)
- return
- }
- if !claims.TOTPValidated {
- if path == b.loginPageURL {
- next.ServeHTTP(w, r)
- return
- }
- r = r.WithContext(context.WithValue(r.Context(), loginWIPKey, true))
- if path == b.totpValidatePageURL {
- next.ServeHTTP(w, r)
- return
- }
- http.Redirect(w, r, b.totpValidatePageURL, http.StatusFound)
- return
- }
- }
- if path == b.loginPageURL || path == b.totpSetupPageURL || path == b.totpValidatePageURL {
- http.Redirect(w, r, b.homePageURLFunc(r, user), http.StatusFound)
- return
- }
- next.ServeHTTP(w, r)
- })
- }
- }
- func GetCurrentUser(r *http.Request) (u interface{}) {
- return r.Context().Value(UserKey)
- }
- func IsLoginWIP(r *http.Request) bool {
- v, ok := r.Context().Value(loginWIPKey).(bool)
- if !ok {
- return false
- }
- return v
- }
|