mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
Merge pull request #1732 from nats-io/rdn-ordering
Match DNs regardless of order when using TLS auth
This commit is contained in:
@@ -5,6 +5,7 @@ package ldap
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
enchex "encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -12,14 +13,14 @@ import (
|
||||
)
|
||||
|
||||
var attributeTypeNames = map[string]string{
|
||||
"2.5.4.6": "C",
|
||||
"2.5.4.10": "O",
|
||||
"2.5.4.11": "OU",
|
||||
"2.5.4.3": "CN",
|
||||
"2.5.4.5": "SERIALNUMBER",
|
||||
"2.5.4.6": "C",
|
||||
"2.5.4.7": "L",
|
||||
"2.5.4.8": "ST",
|
||||
"2.5.4.9": "STREET",
|
||||
"2.5.4.10": "O",
|
||||
"2.5.4.11": "OU",
|
||||
"2.5.4.17": "POSTALCODE",
|
||||
// FIXME: Add others.
|
||||
"0.9.2342.19200300.100.1.25": "DC",
|
||||
@@ -44,7 +45,7 @@ type DN struct {
|
||||
}
|
||||
|
||||
// FromCertSubject takes a pkix.Name from a cert and returns a DN
|
||||
// that uses the same set.
|
||||
// that uses the same set. Does not support multi value RDNs.
|
||||
func FromCertSubject(subject pkix.Name) (*DN, error) {
|
||||
dn := &DN{
|
||||
RDNs: make([]*RelativeDN, 0),
|
||||
@@ -73,6 +74,53 @@ func FromCertSubject(subject pkix.Name) (*DN, error) {
|
||||
return dn, nil
|
||||
}
|
||||
|
||||
// FromRawCertSubject takes a raw subject from a certificate
|
||||
// and uses asn1.Unmarshal to get the individual RDNs in the
|
||||
// original order, including multi-value RDNs.
|
||||
func FromRawCertSubject(rawSubject []byte) (*DN, error) {
|
||||
dn := &DN{
|
||||
RDNs: make([]*RelativeDN, 0),
|
||||
}
|
||||
var rdns pkix.RDNSequence
|
||||
_, err := asn1.Unmarshal(rawSubject, &rdns)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := len(rdns) - 1; i >= 0; i-- {
|
||||
rdn := rdns[i]
|
||||
if len(rdn) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
r := &RelativeDN{}
|
||||
attrs := make([]*AttributeTypeAndValue, 0)
|
||||
for j := len(rdn) - 1; j >= 0; j-- {
|
||||
atv := rdn[j]
|
||||
|
||||
typeName := ""
|
||||
name := atv.Type.String()
|
||||
typeName, ok := attributeTypeNames[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid type name: %+v", name)
|
||||
}
|
||||
value, ok := atv.Value.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid type value: %+v", atv.Value)
|
||||
}
|
||||
attr := &AttributeTypeAndValue{
|
||||
Type: typeName,
|
||||
Value: value,
|
||||
}
|
||||
attrs = append(attrs, attr)
|
||||
}
|
||||
r.Attributes = attrs
|
||||
dn.RDNs = append(dn.RDNs, r)
|
||||
}
|
||||
|
||||
return dn, nil
|
||||
}
|
||||
|
||||
// ParseDN returns a distinguishedName or an error.
|
||||
// The function respects https://tools.ietf.org/html/rfc4514
|
||||
func ParseDN(str string) (*DN, error) {
|
||||
@@ -181,6 +229,29 @@ func (d *DN) Equal(other *DN) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// RDNsMatch returns true if the individual RDNs of the DNs
|
||||
// are the same regardless of ordering.
|
||||
func (d *DN) RDNsMatch(other *DN) bool {
|
||||
if len(d.RDNs) != len(other.RDNs) {
|
||||
return false
|
||||
}
|
||||
|
||||
CheckNextRDN:
|
||||
for _, irdn := range d.RDNs {
|
||||
for _, ordn := range other.RDNs {
|
||||
if (len(irdn.Attributes) == len(ordn.Attributes)) &&
|
||||
(irdn.hasAllAttributes(ordn.Attributes) && ordn.hasAllAttributes(irdn.Attributes)) {
|
||||
// Found the RDN, check if next one matches.
|
||||
continue CheckNextRDN
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find a matching individual RDN, auth fails.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN.
|
||||
// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com"
|
||||
// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com"
|
||||
|
||||
@@ -419,7 +419,7 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) boo
|
||||
} else if hasUsers {
|
||||
// Check if we are tls verify and are mapping users from the client_certificate.
|
||||
if tlsMap {
|
||||
authorized := checkClientTLSCertSubject(c, func(u string, certRDN *ldap.DN, _ bool) (string, bool) {
|
||||
authorized := checkClientTLSCertSubject(c, func(u string, certDN *ldap.DN, _ bool) (string, bool) {
|
||||
// First do literal lookup using the resulting string representation
|
||||
// of RDNSequence as implemented by the pkix package from Go.
|
||||
if u != "" {
|
||||
@@ -431,23 +431,36 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) boo
|
||||
return usr.Username, ok
|
||||
}
|
||||
|
||||
if certRDN == nil {
|
||||
if certDN == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Look through the accounts for an RDN that is equal to the one
|
||||
// Look through the accounts for a DN that is equal to the one
|
||||
// presented by the certificate.
|
||||
dns := make(map[*User]*ldap.DN)
|
||||
for _, usr := range s.users {
|
||||
if !c.connectionTypeAllowed(usr.AllowedConnectionTypes) {
|
||||
continue
|
||||
}
|
||||
// TODO: Use this utility to make a full validation pass
|
||||
// on start in case tlsmap feature is being used.
|
||||
inputRDN, err := ldap.ParseDN(usr.Username)
|
||||
inputDN, err := ldap.ParseDN(usr.Username)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if inputRDN.Equal(certRDN) {
|
||||
if inputDN.Equal(certDN) {
|
||||
user = usr
|
||||
return usr.Username, true
|
||||
}
|
||||
|
||||
// In case it did not match exactly, then collect the DNs
|
||||
// and try to match later in case the DN was reordered.
|
||||
dns[usr] = inputDN
|
||||
}
|
||||
|
||||
// Check in case the DN was reordered.
|
||||
for usr, inputDN := range dns {
|
||||
if inputDN.RDNsMatch(certDN) {
|
||||
user = usr
|
||||
return usr.Username, true
|
||||
}
|
||||
@@ -724,8 +737,9 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool {
|
||||
// the domain components in case there are any.
|
||||
rdn := cert.Subject.ToRDNSequence().String()
|
||||
|
||||
// Match that follows original order from the subject takes precedence.
|
||||
dn, err := ldap.FromCertSubject(cert.Subject)
|
||||
// Match using the raw subject to avoid ignoring attributes.
|
||||
// https://github.com/golang/go/issues/12342
|
||||
dn, err := ldap.FromRawCertSubject(cert.RawSubject)
|
||||
if err == nil {
|
||||
if match, ok := fn("", dn, false); ok {
|
||||
c.Debugf("Using DistinguishedNameMatch for auth [%q]", match)
|
||||
|
||||
28
test/configs/certs/rdns/client-e.key
Normal file
28
test/configs/certs/rdns/client-e.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC0a5HVNplJPJal
|
||||
AXRm8ncYRs9Qpe3q0oW6V0f3URX0smnirK0TjjTdAnsBXAj0Cr9QN7ZIiJ0vAp6z
|
||||
ovB8bFslWZ1g7oi/bRodNiIpkc28oyUY9vLvFxFiMfBdtDATljxEeBQUbPTXugR0
|
||||
QBKFbPvNVRAYxfvagq+DlA5/bX6Src7viNbOViOYPhjgcOGknaBLTpoLd9+q0QFO
|
||||
NDQ3c7T6UA6eqd8o6Yb3NMxYmiWfDkDM3OV+GvUdH7DTAdcW9iHDn5Xj4bj09j/p
|
||||
9wtrIVmsVpygMEvf4HDSYTt+MOCoF5W7EKqy09doThc5HPTSQIllQ2N/Yx23lqI9
|
||||
FNEXJgfHAgMBAAECggEAUmdzQyvd1TpsH89LSB3kUV0+ITq4MPGYjKSCxS3u1kWK
|
||||
4TI3FuBzuqIAZn2PxU8HVG8tvXFQQYFz1N5N8rZW5vdIT1aDdNMzAzaPYecrTcZC
|
||||
EmXwTU1+7hebDmFXOAr9WdRyb2XYapOWpzYAf5poY78/S+FZh9L6sSE1gfQTxJAD
|
||||
qf1pFAj2HMNQ3EbEG8Lg0Cu67GuMp1E0aYZTjbE75do/kukTA4KCjVFmis8zz0K4
|
||||
KNqWMvv1e4lnv70AgIhxBXjYewiHgwWhp+6Hku3NszkjJyqG6DiENKb05K2G9s7c
|
||||
1xhZ9rIJjg2IXtKPsLx2uBA9uBqAztXcbhcQC7PiUQKBgQDe4/38NAD6rqk++HDx
|
||||
SnJQs6N5rGyLWEav0r684kpXMqvtvct8sBb1mptM+92D1XOFLP2sbhi9Yfs8xdIn
|
||||
P0nmO10qO4hDz40NdqfVUookFfZGW0MLnCfAxqSUAfBvzIrrDiVpcQWmm9h7tfXy
|
||||
ToZuz9FCAEQmAinaHk04w677OQKBgQDPOIcOWY5iBPZyPLTNbZm1mM9RzZSWNiW+
|
||||
da39DvB6opCo0WZ9HckzzuCsDAM6HpgPmsBQXyA5ZP6j/JaP4tEsoEjNEiSZUXaZ
|
||||
+ztOM5IDOv61Lnq3WczZxZAVNSkJMNGYAYA6sDnUVDhRLhlY4g8aQ0huWIWdW55g
|
||||
ANm5mwYa/wKBgDLVpuC1b5+85CbTfNbbVtUnE1q1w4/IU17YXt4vcisPCH1Rcy59
|
||||
7s6XM2JMc0oVDaLLDxQbjBLtXOKQb4y5933F/kqah0qH9LCkZkTV7WGrjJ6hQ9pL
|
||||
BBoIdBK5mn+1E93mPQweVd6Y3rfgWTapSCnPxfcannBYv/jaPlx67NapAoGAax5X
|
||||
gm19EuJp20fSVtcvPBaQJUNWagf3nusKU+RjH6Hlkb8dcdPx7Fwm/AkBqguio35l
|
||||
p6Zk7AZvM6og0qR3aNA6kfes/6yC2LpsP9Kcyhq3DEXInftHz9M21h+y5NNdpWwx
|
||||
MyVh34bhzeU8qRvCntrlGFWeTGfOCOanpjCjCVUCgYBRkcm9q7Y9GeDfyy4XEFM6
|
||||
UQM2SNn97Ytq/1B3YvCNC2SCQVXDWFuwNDLeoTWSw+vhuIDdIV8+5tx8w2Av+1MB
|
||||
3tClcyZFNUYOTwEi1N9l41cPuvPsRthlA/10c+C/y/C1KDQzlwmvi6pzG+r8xp2s
|
||||
OGuZfFNwdq/hPA5HZ91Sxg==
|
||||
-----END PRIVATE KEY-----
|
||||
21
test/configs/certs/rdns/client-e.pem
Normal file
21
test/configs/certs/rdns/client-e.pem
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIUKMTp3zRsyUOYWPKNF1VeFwIIiNIwDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHTkFUUyBDQTAeFw0yMDExMTUyMTQzMzVaFw0yNTExMTQy
|
||||
MTQzMzVaMIGGMREwDwYDVQQDDAhKb2huIERvZTEPMA0GA1UEAwwGMTIzNDU2MQ0w
|
||||
CwYDVQQDDARqZG9lMQ4wDAYDVQQLDAVVc2VyczEWMBQGA1UECwwNT3JnYW5pYyBV
|
||||
bml0czEUMBIGCgmSJomT8ixkARkWBGFjbWUxEzARBgoJkiaJk/IsZAEZFgNjb20w
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0a5HVNplJPJalAXRm8ncY
|
||||
Rs9Qpe3q0oW6V0f3URX0smnirK0TjjTdAnsBXAj0Cr9QN7ZIiJ0vAp6zovB8bFsl
|
||||
WZ1g7oi/bRodNiIpkc28oyUY9vLvFxFiMfBdtDATljxEeBQUbPTXugR0QBKFbPvN
|
||||
VRAYxfvagq+DlA5/bX6Src7viNbOViOYPhjgcOGknaBLTpoLd9+q0QFONDQ3c7T6
|
||||
UA6eqd8o6Yb3NMxYmiWfDkDM3OV+GvUdH7DTAdcW9iHDn5Xj4bj09j/p9wtrIVms
|
||||
VpygMEvf4HDSYTt+MOCoF5W7EKqy09doThc5HPTSQIllQ2N/Yx23lqI9FNEXJgfH
|
||||
AgMBAAGjNjA0MDIGA1UdEQQrMCmCCWxvY2FsaG9zdIILZXhhbXBsZS5jb22CD3d3
|
||||
dy5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEApeGRn3qIEpO65GxEWJMI
|
||||
VfgUSRTsTLTGgqLfKXORlp5/75hJGbR39Al3rac2OogHc0hnR3cUL4KaoXqN/W3S
|
||||
lH/JcAqiqblkFmRmUkl5YmthWUgiTtm+To37j/w2owZkoSItpLaYkK8bj035Z6CH
|
||||
ehnuvZmOLQ4vpjwhew7Vawaz4UmoF0GugsgwybppH+j3hX9RkSo298jja5cRzV24
|
||||
iA9jIEFZdzHPYJ/cIK6NW2tu+1ZC61ol6pVif3irBanME/IjEoqFnvwv76MiGvqb
|
||||
T1OTRUf2ny2etK8pgcOcXzsP4P+PqMdZohrqH8aQRQ24rd6LclcarNEAQ5rGo/nu
|
||||
qg==
|
||||
-----END CERTIFICATE-----
|
||||
28
test/configs/certs/rdns/client-f.key
Normal file
28
test/configs/certs/rdns/client-f.key
Normal file
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDReroKzpObO1KW
|
||||
SiPX3bcu6Z20oE53dBGURo58kEcZAErRSkqiieoS/d1xWiVnmTc4oIsJmrIIyNk4
|
||||
rO3l3Mu2lCGfVxhNtFhHrPCdtFctXYRu3c7QAcQCr/HjEzcq2oEtQD83wA16D6PH
|
||||
4PmDfpMhJ0N43FvbDoFOSA61NxxnFkeOyamy6D4QnrIYBxpTvIHdEKCbt2oZsnyD
|
||||
jlmpZdkkTuW51SNXlxz1o++g0+D9R/nzhnojkU4kVVFe0njlLnWrAuN0c2Y4FQuw
|
||||
P1rsMOlUHzpdyVc+KT/Kl33oaEr5pxZujhazDCag47SZgPal9EFyS7VfpyMy457m
|
||||
XEGUHoczAgMBAAECggEAeG6kcv4c4owSiREK1lpDrJbm8iePtSFn0eVWmcqg9YCz
|
||||
guvBSP0dM9n76+U1x//QPaAfD2B+popCSFEzXIm6HLfBNMhv0oyyjFKi6yf5Tr2L
|
||||
G+otsmyxchIRcMllWB/TUF61eanSlbBUKt/u02h70f2uztdxf9kxAf5vZkPO8nxT
|
||||
JSWdkYM4aha56TGFrSxAgLFpmz5rHcp8CH54C0GD4GSafL56hdOV3lfGH2OqwBRf
|
||||
DrXVR857JvTPyoSlkuUTAtQbGTrLVyvIRSbkYHZOFk9JeNkEHl1j1wuvLf5+BHk4
|
||||
olEb4vGjWnuy2EDAStL6QROuyPlQW+Ngd0YPUiiwEQKBgQD+gzh5V1Wp/gRc706a
|
||||
9D22njMmNd/9qJL9n80GJnpRNrb8Cp9vXf50SeFMFBlMy6VJbnh9qRcGtI9fvUae
|
||||
ifmWiM08+oFwyAO4HcSY182TDZMokvARy37XtR7OZVkDootoLz+zlHa0s2eLyIa8
|
||||
NcUzJI5OEeQeq+o+UXlgZ3FbRwKBgQDStCGlm6ptY9RDCDhV2ruep3j5G/V3T8Bm
|
||||
93gbHp+2EBQfUu9fSY1h2K/6bcZff4Thqcd5TtF/zpG0DQ7jseYcg9nwlKzUF0w8
|
||||
4tYCpQJj+4cHjx9bHNsDLw/7a92jesU4kjah7Tt8JUmEt8lYdXYTzokE/2hs7Ay2
|
||||
NsevLgIStQKBgQDJdsusWXKI5ndDrXaWeAGl3eJ1O64710XLl8QuOyUVxm7gYfRE
|
||||
rq2uFZFOrJY+UPFciCK+rat5dlILogMVmfhErbNwsobl5J31DzNBHYov/k3fjziT
|
||||
jXaxf0CMdnMYyoD5jnUpTLsOXPj5EFl/AD1CN4yhxc3Cbak1fT7MDfYQHwKBgAPN
|
||||
qpnRsIbe+XLoUBQEqcRYY4+jmI+5ydBSAUIEEH/51FMobRe8PSgaADs2BhGtPJnS
|
||||
Nb6T1KZI9UpZvf4QNQYovyNfm6sMbJzgv1o23k8tuCdDxx4e7DknfVNdhBeyXKMD
|
||||
yKatoJhCGAykQKcvH52F6eVEMv9cV3JmlL4tx23NAoGBAJCrkp0nZhYdeIGNAOqW
|
||||
vHgHhnXxsqiK+yZ+V4tAUR7c0tr+l7xWxFlVZiXax3bXEMfoyzS3yGlEQoFANvVw
|
||||
afN3t/pIox6IYChUrJiRHy58rSOGEEhgWfVOQ9xD1qLfd1aDCtroFjTvbsRYv7Vg
|
||||
mvMiw5rle3jP3qtjDkg+9U9T
|
||||
-----END PRIVATE KEY-----
|
||||
20
test/configs/certs/rdns/client-f.pem
Normal file
20
test/configs/certs/rdns/client-f.pem
Normal file
@@ -0,0 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDOjCCAiKgAwIBAgIUKMTp3zRsyUOYWPKNF1VeFwIIiNMwDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHTkFUUyBDQTAeFw0yMDExMTUyMzQ4NTVaFw0yNTExMTQy
|
||||
MzQ4NTVaMGQxEzARBgoJkiaJk/IsZAEZFgNvcmcxFzAVBgoJkiaJk/IsZAEZFgdP
|
||||
cGVuU1NMMSEwDAYDVQQKDAV1c2VyczARBgoJkiaJk/IsZAEZFgNERVYxETAPBgNV
|
||||
BAMMCEpvaG4gRG9lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Xq6
|
||||
Cs6TmztSlkoj1923LumdtKBOd3QRlEaOfJBHGQBK0UpKoonqEv3dcVolZ5k3OKCL
|
||||
CZqyCMjZOKzt5dzLtpQhn1cYTbRYR6zwnbRXLV2Ebt3O0AHEAq/x4xM3KtqBLUA/
|
||||
N8ANeg+jx+D5g36TISdDeNxb2w6BTkgOtTccZxZHjsmpsug+EJ6yGAcaU7yB3RCg
|
||||
m7dqGbJ8g45ZqWXZJE7ludUjV5cc9aPvoNPg/Uf584Z6I5FOJFVRXtJ45S51qwLj
|
||||
dHNmOBULsD9a7DDpVB86XclXPik/ypd96GhK+acWbo4WswwmoOO0mYD2pfRBcku1
|
||||
X6cjMuOe5lxBlB6HMwIDAQABozYwNDAyBgNVHREEKzApgglsb2NhbGhvc3SCC2V4
|
||||
YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAAtb
|
||||
cxttYaief3XTMyFa2/dqF6JO47pTCYuCF1i3jL6sPokm2k0L4aCJZTthuUwHBppK
|
||||
fWWGEfERpD1GnEJPW65BRZYFEYFdLEGvT8u9UAnuwbZK/rGSp6K/P2bhCrWZt2qy
|
||||
eA/WQNnWDJ9mXAH6nrJCDPd1ReFr/gidvtw7PJI7pqvu6/oi0H5VpR/RWRHZieWd
|
||||
UplTd2yt3vLaBX592oybfaA5bGQ/lbNaxvZniwUjmR069EvyW5WCGCR0+AON1NxP
|
||||
y5x22lf2HxvxHVDxUb1FTHYvRduy0zbpmYKpjfRXS2IY6fto246Xhv90NBDzgWP1
|
||||
K3erVOvmsj6nNnfcE/A=
|
||||
-----END CERTIFICATE-----
|
||||
206
test/tls_test.go
206
test/tls_test.go
@@ -1540,7 +1540,10 @@ func TestTLSClientAuthWithRDNSequence(t *testing.T) {
|
||||
users = [
|
||||
{ user = "CN=*.example.com,OU=NATS,O=NATS,L=Los Angeles,ST=CA,C=US,DC=example,DC=com",
|
||||
permissions = { subscribe = { deny = ">" }} }
|
||||
|
||||
# This should take precedence since it is in the RFC2253 order.
|
||||
{ user = "DC=com,DC=example,CN=*.example.com,O=NATS,OU=NATS,L=Los Angeles,ST=CA,C=US" }
|
||||
|
||||
{ user = "CN=*.example.com,OU=NATS,O=NATS,L=Los Angeles,ST=CA,C=US",
|
||||
permissions = { subscribe = { deny = ">" }} }
|
||||
]
|
||||
@@ -1553,6 +1556,209 @@ func TestTLSClientAuthWithRDNSequence(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and RDN includes multiple CN elements",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "DC=com,DC=acme,OU=Organic Units,OU=Users,CN=jdoe,CN=123456,CN=John Doe" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/CN=John Doe/CN=123456/CN=jdoe/OU=Users/OU=Organic Units/DC=acme/DC=com"
|
||||
// Go: CN=jdoe,OU=Users+OU=Organic Units
|
||||
// RFC2253: DC=com,DC=acme,OU=Organic Units,OU=Users,CN=jdoe,CN=123456,CN=John Doe
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-e.pem", "./configs/certs/rdns/client-e.key"),
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe"
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN but there is no match",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "CN=John Doe,DC=DEV,DC=OpenSSL,DC=org" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe" -multivalue-rdn
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
errors.New("nats: Authorization Violation"),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN that are reordered",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "CN=John Doe,O=users+DC=DEV,DC=OpenSSL,DC=org" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe" -multivalue-rdn
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
content := fmt.Sprintf(test.config, `
|
||||
tls {
|
||||
cert_file: "configs/certs/rdns/server.pem"
|
||||
key_file: "configs/certs/rdns/server.key"
|
||||
ca_file: "configs/certs/rdns/ca.pem"
|
||||
timeout: 5
|
||||
verify_and_map: true
|
||||
}
|
||||
`)
|
||||
conf := createConfFile(t, []byte(content))
|
||||
defer os.Remove(conf)
|
||||
s, opts := RunServerWithConfig(conf)
|
||||
defer s.Shutdown()
|
||||
|
||||
nc, err := nats.Connect(fmt.Sprintf("tls://localhost:%d", opts.Port),
|
||||
test.certs,
|
||||
nats.RootCAs("./configs/certs/rdns/ca.pem"),
|
||||
)
|
||||
if test.err == nil && err != nil {
|
||||
t.Errorf("Expected to connect, got %v", err)
|
||||
} else if test.err != nil && err == nil {
|
||||
t.Errorf("Expected error on connect")
|
||||
} else if test.err != nil && err != nil {
|
||||
// Error on connect was expected
|
||||
if test.err.Error() != err.Error() {
|
||||
t.Errorf("Expected error %s, got: %s", test.err, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
nc.Subscribe("ping", func(m *nats.Msg) {
|
||||
m.Respond([]byte("pong"))
|
||||
})
|
||||
nc.Flush()
|
||||
|
||||
_, err = nc.Request("ping", []byte("ping"), 250*time.Millisecond)
|
||||
if test.rerr != nil && err == nil {
|
||||
t.Errorf("Expected error getting response")
|
||||
} else if test.rerr == nil && err != nil {
|
||||
t.Errorf("Expected response")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSClientAuthWithRDNSequenceReordered(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
config string
|
||||
certs nats.Option
|
||||
err error
|
||||
rerr error
|
||||
}{
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN that are reordered",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "DC=org,DC=OpenSSL,O=users+DC=DEV,CN=John Doe" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe" -multivalue-rdn
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN that are reordered but not equal RDNs",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "DC=org,DC=OpenSSL,O=users,CN=John Doe" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe" -multivalue-rdn
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
errors.New("nats: Authorization Violation"),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"connect with tls and DN includes a multi value RDN that are reordered but not equal RDNs",
|
||||
`
|
||||
port: -1
|
||||
%s
|
||||
|
||||
authorization {
|
||||
users = [
|
||||
{ user = "DC=OpenSSL, DC=org, O=users, CN=John Doe" }
|
||||
]
|
||||
}
|
||||
`,
|
||||
//
|
||||
// OpenSSL: -subj "/DC=org/DC=OpenSSL/DC=DEV+O=users/CN=John Doe" -multivalue-rdn
|
||||
// Go: CN=John Doe,O=users
|
||||
// RFC2253: CN=John Doe,DC=DEV+O=users,DC=OpenSSL,DC=org
|
||||
//
|
||||
nats.ClientCert("./configs/certs/rdns/client-f.pem", "./configs/certs/rdns/client-f.key"),
|
||||
errors.New("nats: Authorization Violation"),
|
||||
nil,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
content := fmt.Sprintf(test.config, `
|
||||
|
||||
Reference in New Issue
Block a user