1+ package mgo
2+
3+ import (
4+ "crypto/tls"
5+ "crypto/x509"
6+ "io/ioutil"
7+ "net"
8+ "sync"
9+ )
10+
11+ func ExampleCredential_x509Authentication () {
12+ // MongoDB follows RFC2253 for the ordering of the DN - if the order is
13+ // incorrect when creating the user in Mongo, the client will not be able to
14+ // connect.
15+ //
16+ // The best way to generate the DN with the correct ordering is with
17+ // openssl:
18+ //
19+ // openssl x509 -in client.crt -inform PEM -noout -subject -nameopt RFC2253
20+ // subject= CN=Example App,OU=MongoDB Client Authentication,O=GlobalSign,C=GB
21+ //
22+ //
23+ // And then create the user in MongoDB with the above DN:
24+ //
25+ // db.getSiblingDB("$external").runCommand({
26+ // createUser: "CN=Example App,OU=MongoDB Client Authentication,O=GlobalSign,C=GB",
27+ // roles: [
28+ // { role: 'readWrite', db: 'bananas' },
29+ // { role: 'userAdminAnyDatabase', db: 'admin' }
30+ // ],
31+ // writeConcern: { w: "majority" , wtimeout: 5000 }
32+ // })
33+ //
34+ //
35+ // References:
36+ // - https://docs.mongodb.com/manual/tutorial/configure-x509-client-authentication/
37+ // - https://docs.mongodb.com/manual/core/security-x.509/
38+ //
39+
40+ // Read in the PEM encoded X509 certificate.
41+ //
42+ // See the client.pem file at the path below.
43+ clientCertPEM , err := ioutil .ReadFile ("harness/certs/client.pem" )
44+
45+ // Read in the PEM encoded private key.
46+ clientKeyPEM , err := ioutil .ReadFile ("harness/certs/client.key" )
47+
48+ // Parse the private key, and the public key contained within the
49+ // certificate.
50+ clientCert , err := tls .X509KeyPair (clientCertPEM , clientKeyPEM )
51+
52+ // Parse the actual certificate data
53+ clientCert .Leaf , err = x509 .ParseCertificate (clientCert .Certificate [0 ])
54+
55+ // Use the cert to set up a TLS connection to Mongo
56+ tlsConfig := & tls.Config {
57+ Certificates : []tls.Certificate {clientCert },
58+
59+ // This is set to true so the example works within the test
60+ // environment.
61+ //
62+ // DO NOT set InsecureSkipVerify to true in a production
63+ // environment - if you use an untrusted CA/have your own, load
64+ // its certificate into the RootCAs value instead.
65+ //
66+ // RootCAs: myCAChain,
67+ InsecureSkipVerify : true ,
68+ }
69+
70+ // Connect to Mongo using TLS
71+ host := "localhost:40003"
72+ session , err := DialWithInfo (& DialInfo {
73+ Addrs : []string {host },
74+ DialServer : func (addr * ServerAddr ) (net.Conn , error ) {
75+ return tls .Dial ("tcp" , host , tlsConfig )
76+ },
77+ })
78+
79+ // Authenticate using the certificate
80+ cred := & Credential {Certificate : tlsConfig .Certificates [0 ].Leaf }
81+ if err := session .Login (cred ); err != nil {
82+ panic (err )
83+ }
84+
85+ // Done! Use mgo as normal from here.
86+ //
87+ // You should actually check the error code at each step.
88+ _ = err
89+ }
90+
91+ func ExampleSession_concurrency () {
92+ // This example shows the best practise for concurrent use of a mgo session.
93+ //
94+ // Internally mgo maintains a connection pool, dialling new connections as
95+ // required.
96+ //
97+ // Some general suggestions:
98+ // - Define a struct holding the original session, database name and
99+ // collection name instead of passing them explicitly.
100+ // - Define an interface abstracting your data access instead of exposing
101+ // mgo to your application code directly.
102+ // - Limit concurrency at the application level, not with SetPoolLimit().
103+
104+ // This will be our concurrent worker
105+ var doStuff = func (wg * sync.WaitGroup , session * Session ) {
106+ defer wg .Done ()
107+
108+ // Copy the session - if needed this will dial a new connection which
109+ // can later be reused.
110+ //
111+ // Calling close returns the connection to the pool.
112+ conn := session .Copy ()
113+ defer conn .Close ()
114+
115+ // Do something(s) with the connection
116+ _ , _ = conn .DB ("" ).C ("my_data" ).Count ()
117+ }
118+
119+ ///////////////////////////////////////////////
120+
121+ // Dial a connection to Mongo - this creates the connection pool
122+ session , err := Dial ("localhost:40003/my_database" )
123+ if err != nil {
124+ panic (err )
125+ }
126+
127+ // Concurrently do things, passing the session to the worker
128+ wg := & sync.WaitGroup {}
129+ for i := 0 ; i < 10 ; i ++ {
130+ wg .Add (1 )
131+ go doStuff (wg , session )
132+ }
133+ wg .Wait ()
134+
135+ session .Close ()
136+ }
0 commit comments