code.gitea.io/gitea@v1.19.3/modules/context/auth.go (about) 1 // Copyright 2014 The Gogs Authors. All rights reserved. 2 // Copyright 2019 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package context 6 7 import ( 8 "net/http" 9 "strings" 10 11 "code.gitea.io/gitea/models/auth" 12 "code.gitea.io/gitea/modules/log" 13 "code.gitea.io/gitea/modules/setting" 14 "code.gitea.io/gitea/modules/web/middleware" 15 ) 16 17 // ToggleOptions contains required or check options 18 type ToggleOptions struct { 19 SignInRequired bool 20 SignOutRequired bool 21 AdminRequired bool 22 DisableCSRF bool 23 } 24 25 // Toggle returns toggle options as middleware 26 func Toggle(options *ToggleOptions) func(ctx *Context) { 27 return func(ctx *Context) { 28 // Check prohibit login users. 29 if ctx.IsSigned { 30 if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { 31 ctx.Data["Title"] = ctx.Tr("auth.active_your_account") 32 ctx.HTML(http.StatusOK, "user/auth/activate") 33 return 34 } 35 if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { 36 log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) 37 ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") 38 ctx.HTML(http.StatusOK, "user/auth/prohibit_login") 39 return 40 } 41 42 if ctx.Doer.MustChangePassword { 43 if ctx.Req.URL.Path != "/user/settings/change_password" { 44 if strings.HasPrefix(ctx.Req.UserAgent(), "git") { 45 ctx.Error(http.StatusUnauthorized, ctx.Tr("auth.must_change_password")) 46 return 47 } 48 ctx.Data["Title"] = ctx.Tr("auth.must_change_password") 49 ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password" 50 if ctx.Req.URL.Path != "/user/events" { 51 middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) 52 } 53 ctx.Redirect(setting.AppSubURL + "/user/settings/change_password") 54 return 55 } 56 } else if ctx.Req.URL.Path == "/user/settings/change_password" { 57 // make sure that the form cannot be accessed by users who don't need this 58 ctx.Redirect(setting.AppSubURL + "/") 59 return 60 } 61 } 62 63 // Redirect to dashboard if user tries to visit any non-login page. 64 if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { 65 ctx.Redirect(setting.AppSubURL + "/") 66 return 67 } 68 69 if !options.SignOutRequired && !options.DisableCSRF && ctx.Req.Method == "POST" { 70 ctx.csrf.Validate(ctx) 71 if ctx.Written() { 72 return 73 } 74 } 75 76 if options.SignInRequired { 77 if !ctx.IsSigned { 78 if ctx.Req.URL.Path != "/user/events" { 79 middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) 80 } 81 ctx.Redirect(setting.AppSubURL + "/user/login") 82 return 83 } else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { 84 ctx.Data["Title"] = ctx.Tr("auth.active_your_account") 85 ctx.HTML(http.StatusOK, "user/auth/activate") 86 return 87 } 88 } 89 90 // Redirect to log in page if auto-signin info is provided and has not signed in. 91 if !options.SignOutRequired && !ctx.IsSigned && 92 len(ctx.GetCookie(setting.CookieUserName)) > 0 { 93 if ctx.Req.URL.Path != "/user/events" { 94 middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI()) 95 } 96 ctx.Redirect(setting.AppSubURL + "/user/login") 97 return 98 } 99 100 if options.AdminRequired { 101 if !ctx.Doer.IsAdmin { 102 ctx.Error(http.StatusForbidden) 103 return 104 } 105 ctx.Data["PageIsAdmin"] = true 106 } 107 } 108 } 109 110 // ToggleAPI returns toggle options as middleware 111 func ToggleAPI(options *ToggleOptions) func(ctx *APIContext) { 112 return func(ctx *APIContext) { 113 // Check prohibit login users. 114 if ctx.IsSigned { 115 if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { 116 ctx.Data["Title"] = ctx.Tr("auth.active_your_account") 117 ctx.JSON(http.StatusForbidden, map[string]string{ 118 "message": "This account is not activated.", 119 }) 120 return 121 } 122 if !ctx.Doer.IsActive || ctx.Doer.ProhibitLogin { 123 log.Info("Failed authentication attempt for %s from %s", ctx.Doer.Name, ctx.RemoteAddr()) 124 ctx.Data["Title"] = ctx.Tr("auth.prohibit_login") 125 ctx.JSON(http.StatusForbidden, map[string]string{ 126 "message": "This account is prohibited from signing in, please contact your site administrator.", 127 }) 128 return 129 } 130 131 if ctx.Doer.MustChangePassword { 132 ctx.JSON(http.StatusForbidden, map[string]string{ 133 "message": "You must change your password. Change it at: " + setting.AppURL + "/user/change_password", 134 }) 135 return 136 } 137 } 138 139 // Redirect to dashboard if user tries to visit any non-login page. 140 if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" { 141 ctx.Redirect(setting.AppSubURL + "/") 142 return 143 } 144 145 if options.SignInRequired { 146 if !ctx.IsSigned { 147 // Restrict API calls with error message. 148 ctx.JSON(http.StatusForbidden, map[string]string{ 149 "message": "Only signed in user is allowed to call APIs.", 150 }) 151 return 152 } else if !ctx.Doer.IsActive && setting.Service.RegisterEmailConfirm { 153 ctx.Data["Title"] = ctx.Tr("auth.active_your_account") 154 ctx.HTML(http.StatusOK, "user/auth/activate") 155 return 156 } 157 if ctx.IsSigned && ctx.IsBasicAuth { 158 if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) { 159 return // Skip 2FA 160 } 161 twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID) 162 if err != nil { 163 if auth.IsErrTwoFactorNotEnrolled(err) { 164 return // No 2FA enrollment for this user 165 } 166 ctx.InternalServerError(err) 167 return 168 } 169 otpHeader := ctx.Req.Header.Get("X-Gitea-OTP") 170 ok, err := twofa.ValidateTOTP(otpHeader) 171 if err != nil { 172 ctx.InternalServerError(err) 173 return 174 } 175 if !ok { 176 ctx.JSON(http.StatusForbidden, map[string]string{ 177 "message": "Only signed in user is allowed to call APIs.", 178 }) 179 return 180 } 181 } 182 } 183 184 if options.AdminRequired { 185 if !ctx.Doer.IsAdmin { 186 ctx.JSON(http.StatusForbidden, map[string]string{ 187 "message": "You have no permission to request for this.", 188 }) 189 return 190 } 191 ctx.Data["PageIsAdmin"] = true 192 } 193 } 194 }