3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 18:52:41 +01:00

fix a bug

In the previous commit, the client would receive a failure message but would
actually remain logged in after an authzid/authcid mismatch. This was a
correctness rather than a security issue, but now it's fixed so that the client
never logs in in the first place.
This commit is contained in:
Shivaram Lingamneni 2019-12-25 15:06:26 -05:00
parent c8ccf94936
commit 33c8b2177e
4 changed files with 28 additions and 19 deletions

View File

@ -971,7 +971,7 @@ func (am *AccountManager) ChannelsForAccount(account string) (channels []string)
return unmarshalRegisteredChannels(channelStr) return unmarshalRegisteredChannels(channelStr)
} }
func (am *AccountManager) AuthenticateByCertFP(client *Client) error { func (am *AccountManager) AuthenticateByCertFP(client *Client, authzid string) error {
if client.certfp == "" { if client.certfp == "" {
return errAccountInvalidCredentials return errAccountInvalidCredentials
} }
@ -991,6 +991,10 @@ func (am *AccountManager) AuthenticateByCertFP(client *Client) error {
return err return err
} }
if authzid != "" && authzid != account {
return errAuthzidAuthcidMismatch
}
// ok, we found an account corresponding to their certificate // ok, we found an account corresponding to their certificate
clientAccount, err := am.LoadAccount(account) clientAccount, err := am.LoadAccount(account)
if err != nil { if err != nil {

View File

@ -27,6 +27,7 @@ var (
errAccountVerificationInvalidCode = errors.New("Invalid account verification code") errAccountVerificationInvalidCode = errors.New("Invalid account verification code")
errAccountUpdateFailed = errors.New(`Error while updating your account information`) errAccountUpdateFailed = errors.New(`Error while updating your account information`)
errAccountMustHoldNick = errors.New(`You must hold that nickname in order to register it`) errAccountMustHoldNick = errors.New(`You must hold that nickname in order to register it`)
errAuthzidAuthcidMismatch = errors.New(`authcid and authzid must be the same`)
errCallbackFailed = errors.New("Account verification could not be sent") errCallbackFailed = errors.New("Account verification could not be sent")
errCertfpAlreadyExists = errors.New(`An account already exists for your certificate fingerprint`) errCertfpAlreadyExists = errors.New(`An account already exists for your certificate fingerprint`)
errChannelNotOwnedByAccount = errors.New("Channel not owned by the specified account") errChannelNotOwnedByAccount = errors.New("Channel not owned by the specified account")

View File

@ -446,13 +446,14 @@ func authPlainHandler(server *Server, client *Client, mechanism string, value []
} }
func authErrorToMessage(server *Server, err error) (msg string) { func authErrorToMessage(server *Server, err error) (msg string) {
if err == errAccountDoesNotExist || err == errAccountUnverified || err == errAccountInvalidCredentials { switch err {
msg = err.Error() case errAccountDoesNotExist, errAccountUnverified, errAccountInvalidCredentials, errAuthzidAuthcidMismatch:
} else { return err.Error()
default:
// don't expose arbitrary error messages to the user
server.logger.Error("internal", "sasl authentication failure", err.Error()) server.logger.Error("internal", "sasl authentication failure", err.Error())
msg = "Unknown" return "Unknown"
} }
return
} }
// AUTHENTICATE EXTERNAL // AUTHENTICATE EXTERNAL
@ -462,24 +463,27 @@ func authExternalHandler(server *Server, client *Client, mechanism string, value
return false return false
} }
err := server.accounts.AuthenticateByCertFP(client) // EXTERNAL doesn't carry an authentication ID (this is determined from the
// certificate), but does carry an optional authorization ID.
var authzid string
var err error
if len(value) != 0 {
authzid, err = CasefoldName(string(value))
if err != nil {
err = errAuthzidAuthcidMismatch
}
}
if err == nil {
err = server.accounts.AuthenticateByCertFP(client, authzid)
}
if err != nil { if err != nil {
msg := authErrorToMessage(server, err) msg := authErrorToMessage(server, err)
rb.Add(nil, server.name, ERR_SASLFAIL, client.nick, fmt.Sprintf("%s: %s", client.t("SASL authentication failed"), client.t(msg))) rb.Add(nil, server.name, ERR_SASLFAIL, client.nick, fmt.Sprintf("%s: %s", client.t("SASL authentication failed"), client.t(msg)))
return false return false
} }
// EXTERNAL doesn't carry an authentication ID (this is determined from the
// certificate), but does carry an optional authorization ID.
if len(value) != 0 {
authcid := client.Account()
cfAuthzid, err := CasefoldName(string(value))
if err != nil || cfAuthzid != authcid {
rb.Add(nil, server.name, ERR_SASLFAIL, client.Nick(), client.t("SASL authentication failed: authcid and authzid should be the same"))
return false
}
}
sendSuccessfulAccountAuth(client, rb, false, true) sendSuccessfulAccountAuth(client, rb, false, true)
return false return false
} }

View File

@ -536,7 +536,7 @@ func nsIdentifyHandler(server *Server, client *Client, command string, params []
// try certfp // try certfp
if !loginSuccessful && client.certfp != "" { if !loginSuccessful && client.certfp != "" {
err := server.accounts.AuthenticateByCertFP(client) err := server.accounts.AuthenticateByCertFP(client, "")
loginSuccessful = (err == nil) loginSuccessful = (err == nil)
} }