unable to authenticate with mongodb golang driver - mongodb

I'm using mongodb community version 4.2.13 and go driver version 1.5.
My go application is running on the same host as db, but getting the following error when trying to make a connection:
connection() error occured during connection handshake: auth error:
sasl conversation error: unable to authenticate using mechanism
"SCRAM-SHA-256": (AuthenticationFailed) Authentication failed.
Here is how I created the admin account:
use admin
db.createUser({
user: "admin1",
pwd: "passwd12#$",
roles: ["root"],
mechanisms: ["SCRAM-SHA-256"]
})
db.system.users.update(
{ _id: "admin.admin1", "db": "admin" },
{
$addToSet: {
authenticationRestrictions: { clientSource: ["127.0.0.1"] }
}
}
)
Go app code snippet
package main
import (
"context"
"fmt"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
uri := fmt.Sprintf(
"mongodb://%s:%s#%s:%d/admin?authSource=admin&authMechanism=SCRAM-SHA-256",
"admin1",
"passwd12#$",
"127.0.0.1",
27017,
)
// Prints "mongodb://admin1:passwd12#$#127.0.0.1:27017/admin?authSource=admin&authMechanism=SCRAM-SHA-256"
fmt.Println(uri)
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
defer cancel()
client, err := mongo.Connect(
ctx,
options.Client().ApplyURI(uri),
)
if err != nil {
panic(err)
}
defer func() {
err = client.Disconnect(ctx)
if err != nil {
panic(err)
}
}()
err = client.Ping(ctx, nil)
if err != nil {
panic(err)
}
fmt.Println("pinged")
}
I tried the following, but all of them didn't work:
Encoding username and password using url.QueryEscape
Trying "localhost" instead of "127.0.0.1"
Removing "authMechanism=SCRAM-SHA-256" in uri
As a side note, connecting to the Mongo shell with the exact same uri, and that worked.

Add ssl=false to your uri. Worked for me

Based on MongoDB documentation for the authentication process, there is a parameter to identify which database is used for authentication besides the target database on the URI.
While in mongoshell you can use this line
mongo "mongodb://Admin:${DBPASSWORD}#<host>:<port>/admin?authSource=admin"
I used that information to add ?authSource=admin to my CONNECTION_URL
CONNECTION_URL=mongodb://root:example#mongo:27017/my_database?retryWrites=true&w=majority&authSource=admin
That worked for me. Hope it does for you too.
For detailed information please review https://www.mongodb.com/features/mongodb-authentication

You could try using 'options.Credential' to pass the authentication settings.
Seems like a cleaner way than formatting an URI that needs to be parsed later on.
https://docs.mongodb.com/drivers/go/current/fundamentals/auth/
clientOpts := options.Client().SetHosts(
[]string{"localhost:27017"},
).SetAuth(
options.Credential{
AuthSource: "<authenticationDb>",
AuthMechanism: "SCRAM-SHA-256",
Username: "<username>",
Password: "<password>",
}
)
client, err := mongo.Connect(context.TODO(), clientOpts)

Related

how to connect with mongodb in go using atlas?

I am getting a server selection timeout while connecting to mongodb.Any help is appreciated.
selection error: server selection timeout, current topology: { Type:
ReplicaSetNoPrimary, Servers: [{ Addr:
ac-pjyudwq-shard-00-01.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.6.207.111:27017: i/o timeout }, { Addr:
ac-pjyudwq-shard-00-00.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.7.150.83:27017: i/o timeout }, { Addr:
ac-pjyudwq-shard-00-02.1bnb2bm.mongodb.net:27017, Type: Unknown, Last
error: dial tcp 3.7.137.42:27017: i/o timeout }, ] } exit status 1
Code that I used for the connection
const MONGOURL = "mongodb+srv://sai:sai#cluster0.1bnb2bm.mongodb.net/?retryWrites=true&w=majority"
var collection *mongo.Collection
func init() {
fmt.Println("in the init function") var databasename string = "GOAPI"
var collectionname string = "Movies"
client, err: = mongo.Connect(context.TODO(), options.Client().ApplyURI(MONGOURL)) if err != nil {
fmt.Println("unable to get mongo connection ") log.Fatal(err)
}
collection = ( * mongo.Collection)(client.Database(databasename).Collection(collectionname)) fmt.Println("sucessfully collection is created ") doc: = Movie {
Name: "rrr",
Watched: false,
Rating: 9,
Id: "12121"
}
result, err: = collection.InsertOne(context.Background(), doc) if err != nil {
log.Fatal("hey unable to insert one ", err)
}
fmt.Println("sucessfully added : ", result.InsertedID)
// mongo.Connect()`your text`
}
I am hosting my test Atlas cluster on AWS so I wanted to have similar credential management to the AWS process. From the AWS credentials page:
The default provider chain looks for credentials in the following order:
Environment variables.
Shared credentials file.
If your application is running on an Amazon EC2 instance, IAM role for Amazon EC2.
Therefore, I wanted to implement the environment veriable for my simple login to Atlas example. Code below assumes that the following line has been issued at the command line
export MONGO_PW='<your Atlas admin user password>'
Then the following program will verify your connection
package main
import (
"context"
"fmt"
"os"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var username = "<username>"
var host1 = "<atlas host>" // of the form foo.mongodb.net
func main() {
ctx := context.TODO()
pw, ok := os.LookupEnv("MONGO_PW")
if !ok {
fmt.Println("error: unable to find MONGO_PW in the environment")
os.Exit(1)
}
mongoURI := fmt.Sprintf("mongodb+srv://%s:%s#%s", username, pw, host1)
fmt.Println("connection string is:", mongoURI)
// Set client options and connect
clientOptions := options.Client().ApplyURI(mongoURI)
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = client.Ping(ctx, nil)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("Connected to MongoDB!")
}
From here the rest of the tutorial linked in my original question goes smoothly.

MongoDB error with website connection after tried to connect with mongodb database status code 403

I have a problem with mongodb website.
Below i send image with my issue. I built project in Golang where i want to connect with mongodb and if i tried I got error
server selection error: context deadline exceeded, current topology: { Type: Unknown, Servers: [{ Addr: localhost:27017, Type: Unknown, Last error: dial tcp [::1]:27017: connect: connection refused }, ] }
Here I have code where i trying to connect with mongo client
func Connect() *DB {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
err = client.Connect(ctx)
return &DB{
client: client,
}
}
Error on site
Not sure to which MongoDB you are trying to connect. In your code example, the DB is on your local machine.
Your code is missing the DB credentials.
You can try the following code to connect to the DB and verify your connectivity:
client, err := mongo.Connect(ctx, options.Client().ApplyURI("mongodb://admin:password#localhost:27017"))
if err != nil {
log.Fatal(err)
}
if err = client.Ping(context.TODO(), readpref.Primary()); err != nil {
log.Fatal(err)
}
log.Println("Connected to MongoDB")

How to resolve domain names of remote servers while ssh port-forwarding

I am trying to connect to remote mongodb servers using port forwarding. In mgo.DialInfo, the dial server will return a connection (of type *net.Conn) to the intermediary host and the Addrs would be a string of remote mongodb servers' addresses (a set of seed servers). My question is, if I give the remote IP addresses of these servers, the program works fine and I am able to connect to the remote mongodb servers but since, the IP addresses can change I want to give the domain names of the servers, say mongodbserver1 and mongodbserver2 and when I give that, the program hangs. As far as I understood, the program is trying to resolve the domain names on my local machine which won't work and they need to be resolved on the intermediary host. I want to know how I can do that.
In terms of code, the following works fine,
dialinfo := mgo.DialInfo{
Addrs: {"1.2.3.45","1.2.3.56"}
Database: Mongo1,
Username: User,
Password: Pwd,
Timeout: 60 * time.Second,
DialServer: func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := connectToCluster("172.12.13.145")
if err != nil {
fmt.Println("couldn't connect to the cluster, trying again..")
return nil, err
}
remote, err := conn.Dial("tcp", addr.String())
if err != nil {
fmt.Println("couldn't connect to the mongodb server:", addr.String())
}
return remote, err
},
}
session, err = mgo.DialWithInfo(dialinfo)
but the one below doesn't work
dialinfo := mgo.DialInfo{
Addrs: {"mongodbserver1","mongodbserver2"}
Database: Mongo1,
Username: User,
Password: Pwd,
Timeout: 60 * time.Second,
DialServer: func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := connectToCluster("172.12.13.145")
if err != nil {
fmt.Println("couldn't connect to the cluster, trying again..")
return nil, err
}
remote, err := conn.Dial("tcp", addr.String())
if err != nil {
fmt.Println("couldn't connect to the mongodb server:", addr.String())
}
return remote, err
},
}
session, err = mgo.DialWithInfo(dialinfo)
Configure name resolution to work on your machine. This could mean adding test entries to /etc/hosts (if you're using *nix). Or you could add an entry for your production DNS server to /etc/resolv.conf (again, assuming *nix).

CreateSession: no reachable servers - mgo

I'm trying to connect to MongoDB Atlas free cluster using mgo.
Golang Code -
package main
import (
"fmt"
"gopkg.in/mgo.v2"
"time"
"log"
)
const (
AuthDatabase = "mydatabase"
AuthUserName = "databaseadmin"
AuthPassword = "databasepassword"
ReplicaSetName = "myproject-shard-0"
)
func main(){
MongoDBHosts := []string{
"myproject-shard-00-00-w4vds.mongodb.net:27017",
"myproject-shard-00-01-w4vds.mongodb.net:27017",
"myproject-shard-00-02-w4vds.mongodb.net:27017",
}
mongoDBDialInfo := &mgo.DialInfo{
Addrs: MongoDBHosts,
Timeout: 60 * time.Second,
Database: AuthDatabase,
Username: AuthUserName,
Password: AuthPassword,
ReplicaSetName: ReplicaSetName,
}
mongoSession, err := mgo.DialWithInfo(mongoDBDialInfo)
if err != nil {
log.Fatalf("CreateSession: %s\n", err)
}
defer mongoSession.Close()
fmt.Printf("Connected to replica set %v!\n", mongoSession.LiveServers())
}
Error Message -
CreateSession: no reachable servers
Environment
I'm using mongodb free cluster with Google App Engine GO SDK
To connect to MongoDB Atlas, you need SSL
Prerequisites
TLS/SSL
Clients must have support for TLS/SSL to connect to an Atlas cluster.
Clients must have support for the SNI TLS extension to connect to an Atlas M0 Free Tier cluster.
Whitelist
To access a cluster, you must connect from an IP address on the Atlas group’s IP whitelist. If you need to add an IP address to the whitelist, you can do so in the Connect dialog. You can also add the IP address from the Security tab.
Thus I had to change the following piece of code
mongoDBDialInfo := &mgo.DialInfo{
Addrs: MongoDBHosts,
Timeout: 60 * time.Second,
Database: AuthDatabase,
Username: AuthUserName,
Password: AuthPassword,
ReplicaSetName: ReplicaSetName,
}
mongoDBDialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
return conn, err
}
I had to import the following too
"crypto/tls"
"net"

Connection refused with Go + Postgres on Heroku

I am trying to connect to Heroku's Postgres using a Go. All is working fine locally.
The error I am receiving on Heroku is dial tcp 127.0.0.1:5432: connection refused.
I've confirmed my ability to connect to the database via psql on heroku's command line, and have confirmed that the database url config is correct. The code is clear enough, so I wonder if there is a lower-level problem.
The code is straightforward enough:
import (
"database/sql"
"github.com/coopernurse/gorp"
_ "github.com/lib/pq"
"os"
)
func openDb() *sql.DB {
connection := os.Getenv("DATABASE_URL")
db, err := sql.Open("postgres", connection)
if err != nil {
log.Println(err)
}
return db
}
...and am importing github.com/lib/pq. Go version is 1.1.2.
Heroku + Go is pretty particular about the connection strings. The URL-style doesn't seem to allow specification of sslmode=require, which Heroku insists upon.
The modified version uses pq to parse the URL into a traditional Postgres connection string, and appends the parameter:
import (
"database/sql"
"github.com/lib/pq"
"os"
)
func openDb() *sql.DB {
url := os.Getenv("DATABASE_URL")
connection, _ := pq.ParseURL(url)
connection += " sslmode=require"
db, err := sql.Open("postgres", connection)
if err != nil {
log.Println(err)
}
return db
}