In basic auth check for tokens before call UserSignIn (#5725) (#6083)

* Check first if user/password is a token

* In basic auth check if user/password is a token

* Remove unnecessary else statement

* Changes of fmt
This commit is contained in:
Lauris BH 2019-02-15 10:01:53 +02:00 committed by GitHub
parent 57ab65d922
commit 1d8e56e6bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 44 deletions

View file

@ -135,15 +135,56 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
if len(baHead) > 0 { if len(baHead) > 0 {
auths := strings.Fields(baHead) auths := strings.Fields(baHead)
if len(auths) == 2 && auths[0] == "Basic" { if len(auths) == 2 && auths[0] == "Basic" {
var u *models.User
uname, passwd, _ := base.BasicAuthDecode(auths[1]) uname, passwd, _ := base.BasicAuthDecode(auths[1])
u, err := models.UserSignIn(uname, passwd) // Check if username or password is a token
isUsernameToken := len(passwd) == 0 || passwd == "x-oauth-basic"
// Assume username is token
authToken := uname
if !isUsernameToken {
// Assume password is token
authToken = passwd
}
token, err := models.GetAccessTokenBySHA(authToken)
if err == nil {
if isUsernameToken {
u, err = models.GetUserByID(token.UID)
if err != nil {
log.Error(4, "GetUserByID: %v", err)
return nil, false
}
} else {
u, err = models.GetUserByName(uname)
if err != nil {
log.Error(4, "GetUserByID: %v", err)
return nil, false
}
if u.ID != token.UID {
return nil, false
}
}
token.UpdatedUnix = util.TimeStampNow()
if err = models.UpdateAccessToken(token); err != nil {
log.Error(4, "UpdateAccessToken: %v", err)
}
} else {
if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
log.Error(4, "GetAccessTokenBySha: %v", err)
}
}
if u == nil {
u, err = models.UserSignIn(uname, passwd)
if err != nil { if err != nil {
if !models.IsErrUserNotExist(err) { if !models.IsErrUserNotExist(err) {
log.Error(4, "UserSignIn: %v", err) log.Error(4, "UserSignIn: %v", err)
} }
return nil, false return nil, false
} }
}
ctx.Data["IsApiToken"] = true ctx.Data["IsApiToken"] = true
return u, true return u, true
} }

View file

@ -113,24 +113,24 @@ func HTTP(ctx *context.Context) {
return return
} }
authUser, err = models.UserSignIn(authUsername, authPasswd) // Check if username or password is a token
if err != nil {
if !models.IsErrUserNotExist(err) {
ctx.ServerError("UserSignIn error: %v", err)
return
}
}
if authUser == nil {
isUsernameToken := len(authPasswd) == 0 || authPasswd == "x-oauth-basic" isUsernameToken := len(authPasswd) == 0 || authPasswd == "x-oauth-basic"
// Assume username is token // Assume username is token
authToken := authUsername authToken := authUsername
if !isUsernameToken { if !isUsernameToken {
// Assume password is token // Assume password is token
authToken = authPasswd authToken = authPasswd
}
// Assume password is a token.
token, err := models.GetAccessTokenBySHA(authToken)
if err == nil {
if isUsernameToken {
authUser, err = models.GetUserByID(token.UID)
if err != nil {
ctx.ServerError("GetUserByID", err)
return
}
} else {
authUser, err = models.GetUserByName(authUsername) authUser, err = models.GetUserByName(authUsername)
if err != nil { if err != nil {
if models.IsErrUserNotExist(err) { if models.IsErrUserNotExist(err) {
@ -140,37 +140,37 @@ func HTTP(ctx *context.Context) {
} }
return return
} }
} if authUser.ID != token.UID {
// Assume password is a token.
token, err := models.GetAccessTokenBySHA(authToken)
if err != nil {
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
} else {
ctx.ServerError("GetAccessTokenBySha", err)
}
return
}
if isUsernameToken {
authUser, err = models.GetUserByID(token.UID)
if err != nil {
ctx.ServerError("GetUserByID", err)
return
}
} else if authUser.ID != token.UID {
ctx.HandleText(http.StatusUnauthorized, "invalid credentials") ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
return return
} }
}
token.UpdatedUnix = util.TimeStampNow() token.UpdatedUnix = util.TimeStampNow()
if err = models.UpdateAccessToken(token); err != nil { if err = models.UpdateAccessToken(token); err != nil {
ctx.ServerError("UpdateAccessToken", err) ctx.ServerError("UpdateAccessToken", err)
} }
} else { } else {
_, err = models.GetTwoFactorByUID(authUser.ID) if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
log.Error(4, "GetAccessTokenBySha: %v", err)
}
}
if authUser == nil {
// Check username and password
authUser, err = models.UserSignIn(authUsername, authPasswd)
if err != nil {
if !models.IsErrUserNotExist(err) {
ctx.ServerError("UserSignIn error: %v", err)
return
}
}
if authUser == nil {
ctx.HandleText(http.StatusUnauthorized, "invalid credentials")
return
}
_, err = models.GetTwoFactorByUID(authUser.ID)
if err == nil { if err == nil {
// TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented // TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented
ctx.HandleText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page") ctx.HandleText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page")