111 lines
3.1 KiB
Go
111 lines
3.1 KiB
Go
// Copyright (C) MongoDB, Inc. 2017-present.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
// Ignore gosec warning "Blocklisted import crypto/md5: weak cryptographic primitive". We need
|
|
// to use MD5 here to implement the MONGODB-CR specification.
|
|
/* #nosec G501 */
|
|
"crypto/md5"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
|
|
"go.mongodb.org/mongo-driver/x/mongo/driver"
|
|
"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
|
|
)
|
|
|
|
// MONGODBCR is the mechanism name for MONGODB-CR.
|
|
//
|
|
// The MONGODB-CR authentication mechanism is deprecated in MongoDB 3.6 and removed in
|
|
// MongoDB 4.0.
|
|
const MONGODBCR = "MONGODB-CR"
|
|
|
|
func newMongoDBCRAuthenticator(cred *Cred) (Authenticator, error) {
|
|
return &MongoDBCRAuthenticator{
|
|
DB: cred.Source,
|
|
Username: cred.Username,
|
|
Password: cred.Password,
|
|
}, nil
|
|
}
|
|
|
|
// MongoDBCRAuthenticator uses the MONGODB-CR algorithm to authenticate a connection.
|
|
//
|
|
// The MONGODB-CR authentication mechanism is deprecated in MongoDB 3.6 and removed in
|
|
// MongoDB 4.0.
|
|
type MongoDBCRAuthenticator struct {
|
|
DB string
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// Auth authenticates the connection.
|
|
//
|
|
// The MONGODB-CR authentication mechanism is deprecated in MongoDB 3.6 and removed in
|
|
// MongoDB 4.0.
|
|
func (a *MongoDBCRAuthenticator) Auth(ctx context.Context, cfg *Config) error {
|
|
|
|
db := a.DB
|
|
if db == "" {
|
|
db = defaultAuthDB
|
|
}
|
|
|
|
doc := bsoncore.BuildDocumentFromElements(nil, bsoncore.AppendInt32Element(nil, "getnonce", 1))
|
|
cmd := operation.NewCommand(doc).
|
|
Database(db).
|
|
Deployment(driver.SingleConnectionDeployment{cfg.Connection}).
|
|
ClusterClock(cfg.ClusterClock).
|
|
ServerAPI(cfg.ServerAPI)
|
|
err := cmd.Execute(ctx)
|
|
if err != nil {
|
|
return newError(err, MONGODBCR)
|
|
}
|
|
rdr := cmd.Result()
|
|
|
|
var getNonceResult struct {
|
|
Nonce string `bson:"nonce"`
|
|
}
|
|
|
|
err = bson.Unmarshal(rdr, &getNonceResult)
|
|
if err != nil {
|
|
return newAuthError("unmarshal error", err)
|
|
}
|
|
|
|
doc = bsoncore.BuildDocumentFromElements(nil,
|
|
bsoncore.AppendInt32Element(nil, "authenticate", 1),
|
|
bsoncore.AppendStringElement(nil, "user", a.Username),
|
|
bsoncore.AppendStringElement(nil, "nonce", getNonceResult.Nonce),
|
|
bsoncore.AppendStringElement(nil, "key", a.createKey(getNonceResult.Nonce)),
|
|
)
|
|
cmd = operation.NewCommand(doc).
|
|
Database(db).
|
|
Deployment(driver.SingleConnectionDeployment{cfg.Connection}).
|
|
ClusterClock(cfg.ClusterClock).
|
|
ServerAPI(cfg.ServerAPI)
|
|
err = cmd.Execute(ctx)
|
|
if err != nil {
|
|
return newError(err, MONGODBCR)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *MongoDBCRAuthenticator) createKey(nonce string) string {
|
|
// Ignore gosec warning "Use of weak cryptographic primitive". We need to use MD5 here to
|
|
// implement the MONGODB-CR specification.
|
|
/* #nosec G401 */
|
|
h := md5.New()
|
|
|
|
_, _ = io.WriteString(h, nonce)
|
|
_, _ = io.WriteString(h, a.Username)
|
|
_, _ = io.WriteString(h, mongoPasswordDigest(a.Username, a.Password))
|
|
return fmt.Sprintf("%x", h.Sum(nil))
|
|
}
|