mirror of https://github.com/go-gitea/gitea.git
Fix windows build error (#14263)
* fix build * take flash error message back and fix more windows lint error * performance optimization * own step to check lint for windows Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
parent
4ef5f17a7e
commit
a1c9e8f266
12
.drone.yml
12
.drone.yml
|
@ -33,6 +33,18 @@ steps:
|
||||||
GOSUMDB: sum.golang.org
|
GOSUMDB: sum.golang.org
|
||||||
TAGS: bindata sqlite sqlite_unlock_notify
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
|
||||||
|
- name: lint-backend-windows
|
||||||
|
pull: always
|
||||||
|
image: golang:1.15
|
||||||
|
commands:
|
||||||
|
- make golangci-lint vet
|
||||||
|
environment:
|
||||||
|
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||||
|
GOSUMDB: sum.golang.org
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
GOOS: windows
|
||||||
|
GOARCH: amd64
|
||||||
|
|
||||||
- name: lint-backend-gogit
|
- name: lint-backend-gogit
|
||||||
pull: always
|
pull: always
|
||||||
image: golang:1.15
|
image: golang:1.15
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (b *Basic) IsEnabled() bool {
|
||||||
// "Authorization" header of the request and returns the corresponding user object for that
|
// "Authorization" header of the request and returns the corresponding user object for that
|
||||||
// name/token on successful validation.
|
// name/token on successful validation.
|
||||||
// Returns nil if header is empty or validation fails.
|
// Returns nil if header is empty or validation fails.
|
||||||
func (b *Basic) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
|
func (b *Basic) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
|
||||||
baHead := req.Header.Get("Authorization")
|
baHead := req.Header.Get("Authorization")
|
||||||
if len(baHead) == 0 {
|
if len(baHead) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -40,5 +40,5 @@ type SingleSignOn interface {
|
||||||
// or a new user object (with id = 0) populated with the information that was found
|
// or a new user object (with id = 0) populated with the information that was found
|
||||||
// in the authentication data (username or email).
|
// in the authentication data (username or email).
|
||||||
// Returns nil if verification fails.
|
// Returns nil if verification fails.
|
||||||
VerifyAuthData(http *http.Request, store DataStore, sess SessionStore) *models.User
|
VerifyAuthData(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ func (o *OAuth2) IsEnabled() bool {
|
||||||
// or the "Authorization" header and returns the corresponding user object for that ID.
|
// or the "Authorization" header and returns the corresponding user object for that ID.
|
||||||
// If verification is successful returns an existing user object.
|
// If verification is successful returns an existing user object.
|
||||||
// Returns nil if verification fails.
|
// Returns nil if verification fails.
|
||||||
func (o *OAuth2) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
|
func (o *OAuth2) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
|
||||||
if !models.HasEngine {
|
if !models.HasEngine {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func (r *ReverseProxy) IsEnabled() bool {
|
||||||
// If a username is available in the "setting.ReverseProxyAuthUser" header an existing
|
// If a username is available in the "setting.ReverseProxyAuthUser" header an existing
|
||||||
// user object is returned (populated with username or email found in header).
|
// user object is returned (populated with username or email found in header).
|
||||||
// Returns nil if header is empty.
|
// Returns nil if header is empty.
|
||||||
func (r *ReverseProxy) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
|
func (r *ReverseProxy) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
|
||||||
username := r.getUserName(req)
|
username := r.getUserName(req)
|
||||||
if len(username) == 0 {
|
if len(username) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -39,7 +39,7 @@ func (s *Session) IsEnabled() bool {
|
||||||
// VerifyAuthData checks if there is a user uid stored in the session and returns the user
|
// VerifyAuthData checks if there is a user uid stored in the session and returns the user
|
||||||
// object for that uid.
|
// object for that uid.
|
||||||
// Returns nil if there is no user uid stored in the session.
|
// Returns nil if there is no user uid stored in the session.
|
||||||
func (s *Session) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
|
func (s *Session) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
|
||||||
user := SessionUser(sess)
|
user := SessionUser(sess)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
return user
|
return user
|
||||||
|
|
|
@ -7,19 +7,17 @@ package sso
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"gitea.com/macaron/macaron"
|
|
||||||
"gitea.com/macaron/session"
|
|
||||||
|
|
||||||
gouuid "github.com/google/uuid"
|
gouuid "github.com/google/uuid"
|
||||||
"github.com/quasoft/websspi"
|
"github.com/quasoft/websspi"
|
||||||
|
"github.com/unrolled/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,6 +39,7 @@ var (
|
||||||
// On successful authentication returns a valid user object.
|
// On successful authentication returns a valid user object.
|
||||||
// Returns nil if authentication fails.
|
// Returns nil if authentication fails.
|
||||||
type SSPI struct {
|
type SSPI struct {
|
||||||
|
rnd *render.Render
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init creates a new global websspi.Authenticator object
|
// Init creates a new global websspi.Authenticator object
|
||||||
|
@ -48,8 +47,19 @@ func (s *SSPI) Init() error {
|
||||||
config := websspi.NewConfig()
|
config := websspi.NewConfig()
|
||||||
var err error
|
var err error
|
||||||
sspiAuth, err = websspi.New(config)
|
sspiAuth, err = websspi.New(config)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
s.rnd = render.New(render.Options{
|
||||||
|
Extensions: []string{".tmpl"},
|
||||||
|
Directory: "templates",
|
||||||
|
Funcs: templates.NewFuncMap(),
|
||||||
|
Asset: templates.GetAsset,
|
||||||
|
AssetNames: templates.GetAssetNames,
|
||||||
|
IsDevelopment: setting.RunMode != "prod",
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Free releases resources used by the global websspi.Authenticator object
|
// Free releases resources used by the global websspi.Authenticator object
|
||||||
func (s *SSPI) Free() error {
|
func (s *SSPI) Free() error {
|
||||||
|
@ -65,8 +75,8 @@ func (s *SSPI) IsEnabled() bool {
|
||||||
// If authentication is successful, returs the corresponding user object.
|
// If authentication is successful, returs the corresponding user object.
|
||||||
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
|
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
|
||||||
// response code, as required by the SPNEGO protocol.
|
// response code, as required by the SPNEGO protocol.
|
||||||
func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
|
func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
|
||||||
if !s.shouldAuthenticate(ctx) {
|
if !s.shouldAuthenticate(req) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,22 +86,29 @@ func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionSt
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
userInfo, outToken, err := sspiAuth.Authenticate(req, ctx.Resp)
|
userInfo, outToken, err := sspiAuth.Authenticate(req, w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Authentication failed with error: %v\n", err)
|
log.Warn("Authentication failed with error: %v\n", err)
|
||||||
sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken)
|
sspiAuth.AppendAuthenticateHeader(w, outToken)
|
||||||
|
|
||||||
// Include the user login page in the 401 response to allow the user
|
// Include the user login page in the 401 response to allow the user
|
||||||
// to login with another authentication method if SSPI authentication
|
// to login with another authentication method if SSPI authentication
|
||||||
// fails
|
// fails
|
||||||
addFlashErr(ctx, ctx.Tr("auth.sspi_auth_failed"))
|
store.GetData()["Flash"] = map[string]string{
|
||||||
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
|
"ErrMsg": err.Error(),
|
||||||
ctx.Data["EnableSSPI"] = true
|
}
|
||||||
ctx.HTML(401, string(tplSignIn))
|
store.GetData()["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
|
||||||
|
store.GetData()["EnableSSPI"] = true
|
||||||
|
|
||||||
|
err := s.rnd.HTML(w, 401, string(tplSignIn), templates.BaseVars().Merge(store.GetData()))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if outToken != "" {
|
if outToken != "" {
|
||||||
sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken)
|
sspiAuth.AppendAuthenticateHeader(w, outToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
username := sanitizeUsername(userInfo.Username, cfg)
|
username := sanitizeUsername(userInfo.Username, cfg)
|
||||||
|
@ -110,7 +127,7 @@ func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionSt
|
||||||
log.Error("User '%s' not found", username)
|
log.Error("User '%s' not found", username)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
user, err = s.newUser(ctx, username, cfg)
|
user, err = s.newUser(username, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CreateUser: %v", err)
|
log.Error("CreateUser: %v", err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -118,8 +135,8 @@ func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionSt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure requests to API paths and PWA resources do not create a new session
|
// Make sure requests to API paths and PWA resources do not create a new session
|
||||||
if !isAPIPath(ctx) && !isAttachmentDownload(ctx) {
|
if !isAPIPath(req) && !isAttachmentDownload(req) {
|
||||||
handleSignIn(ctx, sess, user)
|
handleSignIn(w, req, sess, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
@ -146,7 +163,7 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
|
||||||
if path == "/user/login" {
|
if path == "/user/login" {
|
||||||
if req.FormValue("user_name") != "" && req.FormValue("password") != "" {
|
if req.FormValue("user_name") != "" && req.FormValue("password") != "" {
|
||||||
shouldAuth = false
|
shouldAuth = false
|
||||||
} else if ctx.Req.FormValue("auth_with_sspi") == "1" {
|
} else if req.FormValue("auth_with_sspi") == "1" {
|
||||||
shouldAuth = true
|
shouldAuth = true
|
||||||
}
|
}
|
||||||
} else if isInternalPath(req) {
|
} else if isInternalPath(req) {
|
||||||
|
@ -217,20 +234,6 @@ func sanitizeUsername(username string, cfg *models.SSPIConfig) string {
|
||||||
return username
|
return username
|
||||||
}
|
}
|
||||||
|
|
||||||
// addFlashErr adds an error message to the Flash object mapped to a macaron.Context
|
|
||||||
func addFlashErr(ctx *macaron.Context, err string) {
|
|
||||||
fv := ctx.GetVal(reflect.TypeOf(&session.Flash{}))
|
|
||||||
if !fv.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
flash, ok := fv.Interface().(*session.Flash)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
flash.Error(err)
|
|
||||||
ctx.Data["Flash"] = flash
|
|
||||||
}
|
|
||||||
|
|
||||||
// init registers the SSPI auth method as the last method in the list.
|
// init registers the SSPI auth method as the last method in the list.
|
||||||
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
|
// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation
|
||||||
// fails (or if negotiation should continue), which would prevent other authentication methods
|
// fails (or if negotiation should continue), which would prevent other authentication methods
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
// SignedInUser returns the user object of signed user.
|
// SignedInUser returns the user object of signed user.
|
||||||
// It returns a bool value to indicate whether user uses basic auth or not.
|
// It returns a bool value to indicate whether user uses basic auth or not.
|
||||||
func SignedInUser(req *http.Request, ds DataStore, sess SessionStore) (*models.User, bool) {
|
func SignedInUser(req *http.Request, w http.ResponseWriter, ds DataStore, sess SessionStore) (*models.User, bool) {
|
||||||
if !models.HasEngine {
|
if !models.HasEngine {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func SignedInUser(req *http.Request, ds DataStore, sess SessionStore) (*models.U
|
||||||
if !ssoMethod.IsEnabled() {
|
if !ssoMethod.IsEnabled() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
user := ssoMethod.VerifyAuthData(req, ds, sess)
|
user := ssoMethod.VerifyAuthData(req, w, ds, sess)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
_, isBasic := ssoMethod.(*Basic)
|
_, isBasic := ssoMethod.(*Basic)
|
||||||
return user, isBasic
|
return user, isBasic
|
||||||
|
|
|
@ -309,7 +309,7 @@ func Contexter() macaron.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user from session if logged in.
|
// Get user from session if logged in.
|
||||||
ctx.User, ctx.IsBasicAuth = sso.SignedInUser(ctx.Req.Request, ctx, ctx.Session)
|
ctx.User, ctx.IsBasicAuth = sso.SignedInUser(ctx.Req.Request, c.Resp, ctx, ctx.Session)
|
||||||
|
|
||||||
if ctx.User != nil {
|
if ctx.User != nil {
|
||||||
ctx.IsSigned = true
|
ctx.IsSigned = true
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (g *Manager) start() {
|
||||||
|
|
||||||
// Make SVC process
|
// Make SVC process
|
||||||
run := svc.Run
|
run := svc.Run
|
||||||
isInteractive, err := svc.IsAnInteractiveSession()
|
isInteractive, err := svc.IsWindowsService()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to ascertain if running as an Interactive Session: %v", err)
|
log.Error("Unable to ascertain if running as an Interactive Session: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -81,7 +81,9 @@ func (g *Manager) start() {
|
||||||
if isInteractive {
|
if isInteractive {
|
||||||
run = debug.Run
|
run = debug.Run
|
||||||
}
|
}
|
||||||
go run(WindowsServiceName, g)
|
go func() {
|
||||||
|
_ = run(WindowsServiceName, g)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute makes Manager implement svc.Handler
|
// Execute makes Manager implement svc.Handler
|
||||||
|
|
|
@ -23,7 +23,7 @@ func enableVTMode(console windows.Handle) bool {
|
||||||
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
|
// https://docs.microsoft.com/en-us/windows/console/setconsolemode
|
||||||
// It only works on windows 10. Earlier terminals will fail with an err which we will
|
// It only works on windows 10. Earlier terminals will fail with an err which we will
|
||||||
// handle to say don't color
|
// handle to say don't color
|
||||||
mode = mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
err = windows.SetConsoleMode(console, mode)
|
err = windows.SetConsoleMode(console, mode)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ func Recovery() func(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user from session if logged in.
|
// Get user from session if logged in.
|
||||||
user, _ := sso.SignedInUser(req, &store, sess)
|
user, _ := sso.SignedInUser(req, w, &store, sess)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
store.Data["IsSigned"] = true
|
store.Data["IsSigned"] = true
|
||||||
store.Data["SignedUser"] = user
|
store.Data["SignedUser"] = user
|
||||||
|
|
Loading…
Reference in New Issue