2023-01-30 16:27:06 +03:00
package imapserver
import (
"encoding/base64"
"errors"
"strings"
"testing"
"github.com/mjl-/mox/scram"
)
func TestAuthenticatePlain ( t * testing . T ) {
tc := start ( t )
tc . transactf ( "no" , "authenticate bogus " )
tc . transactf ( "bad" , "authenticate plain not base64..." )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000baduser\u0000badpass" ) ) )
tc . xcode ( "AUTHENTICATIONFAILED" )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl@mox.example\u0000badpass" ) ) )
tc . xcode ( "AUTHENTICATIONFAILED" )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl\u0000badpass" ) ) ) // Need email, not account.
tc . xcode ( "AUTHENTICATIONFAILED" )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl@mox.example\u0000test" ) ) )
tc . xcode ( "AUTHENTICATIONFAILED" )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl@mox.example\u0000testtesttest" ) ) )
tc . xcode ( "AUTHENTICATIONFAILED" )
tc . transactf ( "bad" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000" ) ) )
tc . xcode ( "" )
tc . transactf ( "no" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "other\u0000mjl@mox.example\u0000testtest" ) ) )
tc . xcode ( "AUTHORIZATIONFAILED" )
tc . transactf ( "ok" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl@mox.example\u0000testtest" ) ) )
tc . close ( )
tc = start ( t )
tc . transactf ( "ok" , "authenticate plain %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "mjl@mox.example\u0000mjl@mox.example\u0000testtest" ) ) )
tc . close ( )
tc = start ( t )
tc . client . AuthenticatePlain ( "mjl@mox.example" , "testtest" )
tc . close ( )
tc = start ( t )
defer tc . close ( )
tc . cmdf ( "" , "authenticate plain" )
tc . readprefixline ( "+ " )
tc . writelinef ( "*" ) // Aborts.
tc . readstatus ( "bad" )
tc . cmdf ( "" , "authenticate plain" )
tc . readprefixline ( "+" )
tc . writelinef ( "%s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "\u0000mjl@mox.example\u0000testtest" ) ) )
tc . readstatus ( "ok" )
}
func TestAuthenticateSCRAMSHA256 ( t * testing . T ) {
tc := start ( t )
tc . client . AuthenticateSCRAMSHA256 ( "mjl@mox.example" , "testtest" )
tc . close ( )
auth := func ( status string , serverFinalError error , username , password string ) {
t . Helper ( )
sc := scram . NewClient ( username , "" )
clientFirst , err := sc . ClientFirst ( )
tc . check ( err , "scram clientFirst" )
tc . client . LastTag = "x001"
tc . writelinef ( "%s authenticate scram-sha-256 %s" , tc . client . LastTag , base64 . StdEncoding . EncodeToString ( [ ] byte ( clientFirst ) ) )
xreadContinuation := func ( ) [ ] byte {
line , _ , result , rerr := tc . client . ReadContinuation ( )
tc . check ( rerr , "read continuation" )
if result . Status != "" {
tc . t . Fatalf ( "expected continuation" )
}
buf , err := base64 . StdEncoding . DecodeString ( line )
tc . check ( err , "parsing base64 from remote" )
return buf
}
serverFirst := xreadContinuation ( )
clientFinal , err := sc . ServerFirst ( serverFirst , password )
tc . check ( err , "scram clientFinal" )
tc . writelinef ( "%s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( clientFinal ) ) )
serverFinal := xreadContinuation ( )
err = sc . ServerFinal ( serverFinal )
if serverFinalError == nil {
tc . check ( err , "scram serverFinal" )
} else if err == nil || ! errors . Is ( err , serverFinalError ) {
t . Fatalf ( "server final, got err %#v, expected %#v" , err , serverFinalError )
}
2023-01-31 02:22:26 +03:00
if serverFinalError != nil {
tc . writelinef ( "*" )
} else {
tc . writelinef ( "" )
}
2023-01-30 16:27:06 +03:00
_ , result , err := tc . client . Response ( )
tc . check ( err , "read response" )
if string ( result . Status ) != strings . ToUpper ( status ) {
tc . t . Fatalf ( "got status %q, expected %q" , result . Status , strings . ToUpper ( status ) )
}
}
tc = start ( t )
auth ( "no" , scram . ErrInvalidProof , "mjl@mox.example" , "badpass" )
auth ( "no" , scram . ErrInvalidProof , "mjl@mox.example" , "" )
// todo: server aborts due to invalid username. we should probably make client continue with fake determinisitically generated salt and result in error in the end.
// auth("no", nil, "other@mox.example", "testtest")
tc . transactf ( "no" , "authenticate bogus " )
tc . transactf ( "bad" , "authenticate scram-sha-256 not base64..." )
tc . transactf ( "bad" , "authenticate scram-sha-256 %s" , base64 . StdEncoding . EncodeToString ( [ ] byte ( "bad data" ) ) )
tc . close ( )
}