From 4c702ce0ec6e3f45fafd6276fd1eff61493c9b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kraszewski?= Date: Thu, 16 Oct 2014 18:35:35 +0200 Subject: [PATCH 1/4] Added support for cert-only login without user and password --- auth.go | 13 +++++++++++++ connection.go | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/auth.go b/auth.go index 435c94b1..e9083bf2 100644 --- a/auth.go +++ b/auth.go @@ -48,8 +48,21 @@ func (auth *AMQPlainAuth) Response() string { return fmt.Sprintf("LOGIN:%sPASSWORD:%s", auth.Username, auth.Password) } +// CertAuth for RabbitMQ-auth-mechanism-ssl. +type CertAuth struct { +} + +func (me *CertAuth) Mechanism() string { + return "EXTERNAL" +} + +func (me *CertAuth) Response() string { + return fmt.Sprintf("\000*\000*") +} + // Finds the first mechanism preferred by the client that the server supports. func pickSASLMechanism(client []Authentication, serverMechanisms []string) (auth Authentication, ok bool) { + for _, auth = range client { for _, mech := range serverMechanisms { if auth.Mechanism() == mech { diff --git a/connection.go b/connection.go index 252852e8..506bcaed 100644 --- a/connection.go +++ b/connection.go @@ -155,6 +155,25 @@ func DialTLS(url string, amqps *tls.Config) (*Connection, error) { TLSClientConfig: amqps, Locale: defaultLocale, }) + +} + +// DialTLS_CertAuth accepts a string in the AMQP URI format and returns a new +// Connection over TCP using EXTERNAL auth. Defaults to a server heartbeat +// interval of 10 seconds and sets the initial read deadline to 30 seconds. +// +// This mechanism is used, when RabbitMQ is configured for EXTERNAL auth with +// ssl_cert_login plugin for userless/passwordless logons +// +// DialTLS_CertAuth uses the provided tls.Config when encountering an amqps:// +// scheme. +func DialTLS_CertAuth(url string, amqps *tls.Config) (*Connection, error) { + + return DialConfig(url, Config{ + Heartbeat: defaultHeartbeat, + TLSClientConfig: amqps, + SASL: []Authentication{&CertAuth{}}, + }) } // DialConfig accepts a string in the AMQP URI format and a configuration for From 61673124ae180e0f84d5f4857c3863aeeabd3bc1 Mon Sep 17 00:00:00 2001 From: Ugurcan Ergun Date: Fri, 26 Feb 2021 17:12:10 +0900 Subject: [PATCH 2/4] Made changes requested inside PR #121 --- auth.go | 12 ++++++------ connection.go | 41 +++++++++++++++++++++++++++++++++++------ examples_test.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/auth.go b/auth.go index e9083bf2..266218ca 100644 --- a/auth.go +++ b/auth.go @@ -48,21 +48,21 @@ func (auth *AMQPlainAuth) Response() string { return fmt.Sprintf("LOGIN:%sPASSWORD:%s", auth.Username, auth.Password) } -// CertAuth for RabbitMQ-auth-mechanism-ssl. -type CertAuth struct { +// ExternalAuth for RabbitMQ-auth-mechanism-ssl. +type ExternalAuth struct { } -func (me *CertAuth) Mechanism() string { +// Mechanism returns "EXTERNAL" +func (me *ExternalAuth) Mechanism() string { return "EXTERNAL" } -func (me *CertAuth) Response() string { - return fmt.Sprintf("\000*\000*") +func (me *ExternalAuth) Response() string { + return "\000*\000*" } // Finds the first mechanism preferred by the client that the server supports. func pickSASLMechanism(client []Authentication, serverMechanisms []string) (auth Authentication, ok bool) { - for _, auth = range client { for _, mech := range serverMechanisms { if auth.Mechanism() == mech { diff --git a/connection.go b/connection.go index 506bcaed..df6959b6 100644 --- a/connection.go +++ b/connection.go @@ -130,6 +130,33 @@ func DefaultDial(connectionTimeout time.Duration) func(network, addr string) (ne } } +type Option func(*Config) error + +// SetOptions set amqp connection options +func (a *Config) SetOptions(opts ...Option) error { + for _, opt := range opts { + if err := opt(a); err != nil { + return err + } + } + + return nil +} + +func TLS(val *tls.Config) Option { + return func(t *Config) error { + t.TLSClientConfig = val + return nil + } +} + +func Auth(val []Authentication) Option { + return func(t *Config) error { + t.SASL = val + return nil + } +} + // Dial accepts a string in the AMQP URI format and returns a new Connection // over TCP using PlainAuth. Defaults to a server heartbeat interval of 10 // seconds and sets the handshake deadline to 30 seconds. After handshake, @@ -137,11 +164,13 @@ func DefaultDial(connectionTimeout time.Duration) func(network, addr string) (ne // // Dial uses the zero value of tls.Config when it encounters an amqps:// // scheme. It is equivalent to calling DialTLS(amqp, nil). -func Dial(url string) (*Connection, error) { - return DialConfig(url, Config{ +func Dial(url string, opts ...Option) (*Connection, error) { + config := Config{ Heartbeat: defaultHeartbeat, Locale: defaultLocale, - }) + } + config.SetOptions(opts...) + return DialConfig(url, config) } // DialTLS accepts a string in the AMQP URI format and returns a new Connection @@ -158,7 +187,7 @@ func DialTLS(url string, amqps *tls.Config) (*Connection, error) { } -// DialTLS_CertAuth accepts a string in the AMQP URI format and returns a new +// DialTLSExternalAuth accepts a string in the AMQP URI format and returns a new // Connection over TCP using EXTERNAL auth. Defaults to a server heartbeat // interval of 10 seconds and sets the initial read deadline to 30 seconds. // @@ -167,12 +196,12 @@ func DialTLS(url string, amqps *tls.Config) (*Connection, error) { // // DialTLS_CertAuth uses the provided tls.Config when encountering an amqps:// // scheme. -func DialTLS_CertAuth(url string, amqps *tls.Config) (*Connection, error) { +func DialTLSExternalAuth(url string, amqps *tls.Config) (*Connection, error) { return DialConfig(url, Config{ Heartbeat: defaultHeartbeat, TLSClientConfig: amqps, - SASL: []Authentication{&CertAuth{}}, + SASL: []Authentication{&ExternalAuth{}}, }) } diff --git a/examples_test.go b/examples_test.go index 278a6dd1..4567228d 100644 --- a/examples_test.go +++ b/examples_test.go @@ -104,6 +104,36 @@ func ExampleDialTLS() { log.Printf("conn: %v, err: %v", conn, err) } +func ExampleDialwithTLSandExternalAuth() { + // This example assumes you enabled the rabbitmq-auth-mechanism-ssl plugin + // and your RabbitMQ server has TLS enabled + + // The username will be read from the DN or CN fields of the certificate + // you provide, you can see the more detailed information provided here + // https://github.com/rabbitmq/rabbitmq-auth-mechanism-ssl#username-extraction-from-certificate + + cfg := new(tls.Config) + + // see at the top + cfg.RootCAs = x509.NewCertPool() + + if ca, err := ioutil.ReadFile("testca/cacert.pem"); err == nil { + cfg.RootCAs.AppendCertsFromPEM(ca) + } + + // Move the client cert and key to a location specific to your application + // and load them here. + + if cert, err := tls.LoadX509KeyPair("client/cert.pem", "client/key.pem"); err == nil { + cfg.Certificates = append(cfg.Certificates, cert) + } + + // If you don't supply the Auth method as EXTERNAL, connection wouldn't fail and you will be logged in as the guest user. + conn, err := amqp.Dial("amqps://server-name-from-certificate/", amqp.TLS(cfg), amqp.Auth([]amqp.Authentication{&amqp.ExternalAuth{}})) + + log.Printf("conn: %v, err: %v", conn, err) +} + func ExampleChannel_Confirm_bridge() { // This example acts as a bridge, shoveling all messages sent from the source // exchange "log" to destination exchange "log". From 990b989cab71111a39906b832ec62f2d432e10ac Mon Sep 17 00:00:00 2001 From: Ugurcan Ergun Date: Fri, 26 Feb 2021 17:43:15 +0900 Subject: [PATCH 3/4] Corrected lint errors --- auth.go | 1 + connection.go | 3 +++ 2 files changed, 4 insertions(+) diff --git a/auth.go b/auth.go index 266218ca..45f77e62 100644 --- a/auth.go +++ b/auth.go @@ -57,6 +57,7 @@ func (me *ExternalAuth) Mechanism() string { return "EXTERNAL" } +// Response returns zero ? func (me *ExternalAuth) Response() string { return "\000*\000*" } diff --git a/connection.go b/connection.go index df6959b6..38e3ab0f 100644 --- a/connection.go +++ b/connection.go @@ -130,6 +130,7 @@ func DefaultDial(connectionTimeout time.Duration) func(network, addr string) (ne } } +// Option type for Dial type Option func(*Config) error // SetOptions set amqp connection options @@ -143,6 +144,7 @@ func (a *Config) SetOptions(opts ...Option) error { return nil } +// TLS is a wrapper for tls.Config to send as a Dial Option func TLS(val *tls.Config) Option { return func(t *Config) error { t.TLSClientConfig = val @@ -150,6 +152,7 @@ func TLS(val *tls.Config) Option { } } +// Auth is a wrapper for SASL to send as a Dial Option func Auth(val []Authentication) Option { return func(t *Config) error { t.SASL = val From fbbcdd77a321bb26a29821813b5d0b7a37ec15f1 Mon Sep 17 00:00:00 2001 From: Ugurcan Ergun Date: Fri, 26 Feb 2021 17:53:09 +0900 Subject: [PATCH 4/4] Changed test name --- examples_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_test.go b/examples_test.go index 4567228d..4983816a 100644 --- a/examples_test.go +++ b/examples_test.go @@ -104,7 +104,7 @@ func ExampleDialTLS() { log.Printf("conn: %v, err: %v", conn, err) } -func ExampleDialwithTLSandExternalAuth() { +func ExampleDial_withTLSandExternalAuth() { // This example assumes you enabled the rabbitmq-auth-mechanism-ssl plugin // and your RabbitMQ server has TLS enabled