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

504 5.7.4 Unrecognized authentication type #16

Closed
alexcesaro opened this issue Jan 12, 2015 · 18 comments
Closed

504 5.7.4 Unrecognized authentication type #16

alexcesaro opened this issue Jan 12, 2015 · 18 comments

Comments

@alexcesaro
Copy link
Member

From golang-nuts: https://groups.google.com/d/msg/golang-nuts/ywPpNlmSt6U/0Mxttkx9kgQJ

mailer := gomail.NewMailer("smtp.office365.com", "f...@bar.com", "password", 587)

Returns error 504 5.7.4 Unrecognized authentication type

@alexcesaro
Copy link
Member Author

You should try to use you own Auth mechanism.
Create a Login authentication mechanism by copying PlainAuth from the standard library and replace the two instances of PLAIN by LOGIN.

Then use gomail.NewCustomMailer to use your new auth mechanism.
If it works I will update Gomail to automatically use the LOGIN mechanism when PLAIN is not available.

@marcalj
Copy link

marcalj commented Jan 12, 2015

Ok, I'll ping you when I get it. Thanks!

@marcalj
Copy link

marcalj commented Feb 9, 2015

Hey, I found time to work on it! :)

type loginAuth struct {
    identity, username, password string
    host                         string
}

// loginAuth returns an Auth that implements the LOGIN authentication
// mechanism as defined in RFC 4616.
// The returned Auth uses the given username and password to authenticate
// on TLS connections to host and act as identity. Usually identity will be
// left blank to act as username.
func LoginAuth(identity, username, password, host string) smtp.Auth {
    return &loginAuth{identity, username, password, host}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
        if !server.TLS {
            advertised := false
            for _, mechanism := range server.Auth {
                if mechanism == "LOGIN" {
                    advertised = true
                    break
                }
            }
            if !advertised {
                return "", nil, errors.New("unencrypted connection")
            }
        }
        if server.Name != a.host {
            return "", nil, errors.New("wrong host name")
        }
        resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
        return "LOGIN", resp, nil
    }

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
//    log.Println("NEXT: ", fromServer)
    if more {
        // We've already sent everything.
        return nil, errors.New("unexpected server challenge")
    }
    return nil, nil
}

Then, create mailer with this:

mailer := gomail.NewCustomMailer("smtp.office365.com:587", LoginAuth("", "foo@email.com", "password", "smtp.office365.com"))

But I'm getting error from LoginAuth.Next:
unexpected server challenge

If you see the implementation on SwiftMailer the commands sent are with different notation:

AuthPlain: https://github.com/swiftmailer/swiftmailer/blob/master/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php#L41
AuthLogin: https://github.com/swiftmailer/swiftmailer/blob/master/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php#L40

I don't know how to change this... too late :(

Can you help me? Thanks!!!

@marcalj
Copy link

marcalj commented Feb 9, 2015

Ok I think the first command is just AUTH LOGIN and then two more commands with username and password:

$agent->executeCommand("AUTH LOGIN\r\n", array(334));
            $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334));
            $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235));

So, to do this, in LoginAuth.Start we just have to send return "LOGIN", nil, nil and the other commands should be sent in LoginAuth.Next right?

So, two questions, how to know if I'm sending the first (username) or second (password) parameter?
Maybe an step parameter initialized in Start method.

So now the question is how to encode the two commands to the server...

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
    log.Println("NEXT: ", fromServer)
//    if more {
//      // We've already sent everything.
//      return nil, errors.New("unexpected server challenge")
//  }
    if more {
        if (a.authInit == true) {
            a.authInit = false
            return []byte(fmt.Sprintf("%s %x", a.username, 334)), nil
        } else {
            return []byte(fmt.Sprintf("%s %x", a.password, 235)), nil
        }
    }
    return nil, nil
}

Don't know how to set the second parameter of Sprintf. Too late for today.

@alexcesaro
Copy link
Member Author

Sorry I do not have the issue so I cannot help you much.

334 and 235 are not parameters on Sprintf but of executeCommand in the Swiftmailer code. So you should try removing them.

@marcalj
Copy link

marcalj commented Feb 10, 2015

I suppose the spec needs some length or code at the end of the command:
Like http://golang.org/src/net/smtp/auth.go#L99

func (a *cramMD5Auth) Next(fromServer []byte, more bool) ([]byte, error) {
        if more {
            d := hmac.New(md5.New, []byte(a.secret))
            d.Write(fromServer)
            s := make([]byte, 0, d.Size())
            return []byte(fmt.Sprintf("%s %x", a.username, d.Sum(s))), nil
        }
        return nil, nil
    }

I'm just asking for your help because you played with the SMTP protocol right? :)
Thanks anyway!

@marcalj
Copy link

marcalj commented Feb 10, 2015

Yayyyy it works!!!

I just have to follow the spec hehe:
http://www.samlogic.net/articles/smtp-commands-reference-auth.htm

I think I will send a pull request for "net/smtp/auth.go" :) but first I need to clean up things and make some tests.

Thanks!

@marcalj
Copy link

marcalj commented Feb 10, 2015

Ok, while it's accepted as a pull request (if there's a chance) how you will deal with this "bug"?
Meanwhile could be implemented in your library?
How will the NewMailer know and use the AUTH LOGIN mechanism?

@marcalj
Copy link

marcalj commented Feb 10, 2015

Here's the code of LoginAuth:

type loginAuth struct {
    username, password string
}

// loginAuth returns an Auth that implements the LOGIN authentication
// mechanism as defined in RFC 4616.
func LoginAuth(username, password string) smtp.Auth {
    return &loginAuth{username, password}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
    return "LOGIN", nil, nil
}

func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
    command := string(fromServer)
    command = strings.TrimSpace(command)
    command = strings.TrimSuffix(command, ":")
    command = strings.ToLower(command)

    if more {
        if (command == "username") {
            return []byte(fmt.Sprintf("%s", a.username)), nil
        } else if (command == "password") {
            return []byte(fmt.Sprintf("%s", a.password)), nil
        } else {
            // We've already sent everything.
            return nil, fmt.Errorf("unexpected server challenge: %s", command)
        }
    }
    return nil, nil
}

Then call: mailer := gomail.NewCustomMailer("smtp.office365.com:587", LoginAuth("login@email.com", "password")).

Not sure why I don't need to use base64 to decode server commands and encode user and password :/

@alexcesaro
Copy link
Member Author

Good job !

It is a bit difficult to do the fix since I cannot create an account on office365. Could you send the content of:

  • the content of server in your function Start (with fmt.Printf("%#v\n", server) for example)
  • the content of fromServer (with fmt.Printf("%s\n", server) for example) in your Next function
  • the second variable returned by c.Extension("AUTH") here

@marcalj
Copy link

marcalj commented Feb 10, 2015

On Start function fmt.Printf("server(@alexcesaro): %#v\n", server)
On Next function fmt.Printf("fromServer(@alexcesaro): %s\n", string(fromServer))
On getSendMailFunc function fmt.Printf("SendMailFunc(@alexcesaro): %#v\n", secondParameter)

server(@alexcesaro): &smtp.ServerInfo{Name:"smtp.office365.com", TLS:true, Auth:[]string{"LOGIN"}}
fromServer(@alexcesaro): Username:
fromServer(@alexcesaro): Password:
fromServer(@alexcesaro): 2.7.0 Authentication successful target host DB3PR02MB219.eurprd02.prod.outlook.com
SendMailFunc(@alexcesaro): "LOGIN"

@alexcesaro
Copy link
Member Author

Thanks!

I commited a new function on a new branch, can you try it to see if it works? See the readme for more details.

@marcalj
Copy link

marcalj commented Feb 12, 2015

Sorry for the delay! Checked that it works perfectly!!! :D 💃
Which GMail it's working with this new AuthLogin or it was working before? I assume both are using the same login mechanism.

Will you create a new version? How I have to update it?

Thanks!

@marcalj
Copy link

marcalj commented Feb 12, 2015

In case it will be included in SMTP standard library.
https://groups.google.com/forum/#!topic/golang-nuts/Cr5I_J9LhSI

@alexcesaro
Copy link
Member Author

I merged the branch. You can do go get -u gopkg.in/gomail.v1 to get the new version.

Gmail works well on the PLAIN mechanism and using this new auth is not needed.

@marcalj
Copy link

marcalj commented Feb 12, 2015

Perfect! Thanks a lot!

@tappoz
Copy link

tappoz commented Jun 12, 2019

I landed here after receiving the error from the Go standard library net/smtp while using smtp.office365.com on port 587. The alternative solution from @marcalj (LoginAuth - which implements the login as per RFC 4616) works (thanks!).

I am on Go version 1.10.3 and I am a bit surprised this issue (error/bug?) is still in there.
Is this a bug at all or more of a non-standard convention or dialect of SMTP over TLS? I can not find evidence of this kind of problem on the Go standard library.

@pedromorgan
Copy link

see #108 and #104

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants