Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix windows build error #14263

Merged
merged 4 commits into from
Jan 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ steps:
GOSUMDB: sum.golang.org
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
pull: always
image: golang:1.15
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/sso/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (b *Basic) IsEnabled() bool {
// "Authorization" header of the request and returns the corresponding user object for that
// name/token on successful validation.
// 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")
if len(baHead) == 0 {
return nil
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/sso/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ type SingleSignOn interface {
// or a new user object (with id = 0) populated with the information that was found
// in the authentication data (username or email).
// 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
}
2 changes: 1 addition & 1 deletion modules/auth/sso/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (o *OAuth2) IsEnabled() bool {
// or the "Authorization" header and returns the corresponding user object for that ID.
// If verification is successful returns an existing user object.
// 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 {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/sso/reverseproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (r *ReverseProxy) IsEnabled() bool {
// If a username is available in the "setting.ReverseProxyAuthUser" header an existing
// user object is returned (populated with username or email found in header).
// 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)
if len(username) == 0 {
return nil
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/sso/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
// object for that uid.
// 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)
if user != nil {
return user
Expand Down
67 changes: 35 additions & 32 deletions modules/auth/sso/sspi_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ package sso
import (
"errors"
"net/http"
"reflect"
"strings"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"gitea.com/macaron/macaron"
"gitea.com/macaron/session"
"code.gitea.io/gitea/modules/templates"

gouuid "github.com/google/uuid"
"github.com/quasoft/websspi"
"github.com/unrolled/render"
)

const (
Expand All @@ -41,14 +39,26 @@ var (
// On successful authentication returns a valid user object.
// Returns nil if authentication fails.
type SSPI struct {
rnd *render.Render
}

// Init creates a new global websspi.Authenticator object
func (s *SSPI) Init() error {
config := websspi.NewConfig()
var err error
sspiAuth, err = websspi.New(config)
return err
if err != nil {
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
Expand All @@ -65,8 +75,8 @@ func (s *SSPI) IsEnabled() bool {
// If authentication is successful, returs the corresponding user object.
// If negotiation should continue or authentication fails, immediately returns a 401 HTTP
// response code, as required by the SPNEGO protocol.
func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionStore) *models.User {
if !s.shouldAuthenticate(ctx) {
func (s *SSPI) VerifyAuthData(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *models.User {
if !s.shouldAuthenticate(req) {
return nil
}

Expand All @@ -76,22 +86,29 @@ func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionSt
return nil
}

userInfo, outToken, err := sspiAuth.Authenticate(req, ctx.Resp)
userInfo, outToken, err := sspiAuth.Authenticate(req, w)
if err != nil {
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
// to login with another authentication method if SSPI authentication
// fails
addFlashErr(ctx, ctx.Tr("auth.sspi_auth_failed"))
ctx.Data["EnableOpenIDSignIn"] = setting.Service.EnableOpenIDSignIn
ctx.Data["EnableSSPI"] = true
ctx.HTML(401, string(tplSignIn))
store.GetData()["Flash"] = map[string]string{
"ErrMsg": err.Error(),
}
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
}
if outToken != "" {
sspiAuth.AppendAuthenticateHeader(ctx.Resp, outToken)
sspiAuth.AppendAuthenticateHeader(w, outToken)
}

username := sanitizeUsername(userInfo.Username, cfg)
Expand All @@ -110,16 +127,16 @@ func (s *SSPI) VerifyAuthData(req *http.Request, store DataStore, sess SessionSt
log.Error("User '%s' not found", username)
return nil
}
user, err = s.newUser(ctx, username, cfg)
user, err = s.newUser(username, cfg)
if err != nil {
log.Error("CreateUser: %v", err)
return nil
}
}

// Make sure requests to API paths and PWA resources do not create a new session
if !isAPIPath(ctx) && !isAttachmentDownload(ctx) {
handleSignIn(ctx, sess, user)
if !isAPIPath(req) && !isAttachmentDownload(req) {
handleSignIn(w, req, sess, user)
}

return user
Expand All @@ -146,7 +163,7 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
if path == "/user/login" {
if req.FormValue("user_name") != "" && req.FormValue("password") != "" {
shouldAuth = false
} else if ctx.Req.FormValue("auth_with_sspi") == "1" {
} else if req.FormValue("auth_with_sspi") == "1" {
shouldAuth = true
}
} else if isInternalPath(req) {
Expand Down Expand Up @@ -217,20 +234,6 @@ func sanitizeUsername(username string, cfg *models.SSPIConfig) string {
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.
// 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
Expand Down
4 changes: 2 additions & 2 deletions modules/auth/sso/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// SignedInUser returns the user object of signed user.
// 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 {
return nil, false
}
Expand All @@ -22,7 +22,7 @@ func SignedInUser(req *http.Request, ds DataStore, sess SessionStore) (*models.U
if !ssoMethod.IsEnabled() {
continue
}
user := ssoMethod.VerifyAuthData(req, ds, sess)
user := ssoMethod.VerifyAuthData(req, w, ds, sess)
if user != nil {
_, isBasic := ssoMethod.(*Basic)
return user, isBasic
Expand Down
2 changes: 1 addition & 1 deletion modules/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ func Contexter() macaron.Handler {
}

// 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 {
ctx.IsSigned = true
Expand Down
6 changes: 4 additions & 2 deletions modules/graceful/manager_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,17 @@ func (g *Manager) start() {

// Make SVC process
run := svc.Run
isInteractive, err := svc.IsAnInteractiveSession()
isInteractive, err := svc.IsWindowsService()
if err != nil {
log.Error("Unable to ascertain if running as an Interactive Session: %v", err)
return
}
if isInteractive {
run = debug.Run
}
go run(WindowsServiceName, g)
go func() {
_ = run(WindowsServiceName, g)
}()
}

// Execute makes Manager implement svc.Handler
Expand Down
2 changes: 1 addition & 1 deletion modules/log/console_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func enableVTMode(console windows.Handle) bool {
// 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
// handle to say don't color
mode = mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
err = windows.SetConsoleMode(console, mode)
return err == nil
}
Expand Down
2 changes: 1 addition & 1 deletion routers/routes/recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func Recovery() func(next http.Handler) http.Handler {
}

// Get user from session if logged in.
user, _ := sso.SignedInUser(req, &store, sess)
user, _ := sso.SignedInUser(req, w, &store, sess)
if user != nil {
store.Data["IsSigned"] = true
store.Data["SignedUser"] = user
Expand Down