From 593df0650fab3036bf2a889615c57054148023d1 Mon Sep 17 00:00:00 2001 From: Tim Vaillancourt Date: Fri, 3 Aug 2018 17:55:42 +0200 Subject: [PATCH] Add 3.6+ user authenticationRestrictions (#229) * Add 3.6 user authenticationRestrictions * Add struct-field comment * Add struct-field comment #2 * Add struct-field comment #3 * Add documentation link * Fix comment * Fix comment #2 * add to README.md * add to README.md #2 * add to README.md #3 * Add positive/negative authentication restrictions user test * Use denyUser for negative test * Correct message * Fix error match * Fix close on nil/closed session * Simplify test, last change :) * Simplify test, last change :) #2 * Simplify test, last change :) #3 * Fix := error --- README.md | 2 +- auth_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ session.go | 25 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index da6063b0d..b4ca8b1c2 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ A [sub-package](https://godoc.org/github.com/globalsign/mgo/bson) that implement * Support setting `writeConcern` for `findAndModify` operations ([details](https://github.com/globalsign/mgo/pull/185)) * Add `ssl` to the dial string options ([details](https://github.com/globalsign/mgo/pull/184)) * Support connecting via Unix sockets ([details](https://github.com/globalsign/mgo/pull/129)) - +* Support MongoDB User authenticationRestrictions ([details](https://github.com/globalsign/mgo/pull/229)) --- diff --git a/auth_test.go b/auth_test.go index 689812477..793a94009 100644 --- a/auth_test.go +++ b/auth_test.go @@ -341,6 +341,57 @@ func (s *S) TestAuthUpsertUserUpdates(c *C) { c.Assert(err, IsNil) } +func (s *S) TestAuthUpsertUserAuthenticationRestrictions(c *C) { + if !s.versionAtLeast(3, 6) { + c.Skip("UpsertUser with user 'authenticationRestrictions' only works on 3.6+") + } + session, err := mgo.Dial("localhost:40002") + c.Assert(err, IsNil) + defer session.Close() + + admindb := session.DB("admin") + err = admindb.Login("root", "rapadura") + + allowUser := &mgo.User{ + Username: "authRestrictionUser", + Password: "123456", + Roles: []mgo.Role{mgo.RoleReadWrite}, + AuthenticationRestrictions: []mgo.AuthenticationRestriction{ + { + ClientSource: []string{"127.0.0.1"}, + ServerAddress: []string{"127.0.0.1"}, + }, + }, + } + err = admindb.UpsertUser(allowUser) + c.Assert(err, IsNil) + + // Dial again to ensure the positive authentication restriction allows the connection + allowSession, err := mgo.Dial("mongodb://authRestrictionUser:123456@127.0.0.1:40002/admin") + c.Assert(err, IsNil) + c.Assert(allowSession.Ping(), IsNil) + defer allowSession.Close() + + // this user should fail authentication restrictions + denyUser := &mgo.User{ + Username: "denyUser", + Password: "123456", + Roles: []mgo.Role{mgo.RoleReadWrite}, + AuthenticationRestrictions: []mgo.AuthenticationRestriction{ + { + ClientSource: []string{"1.2.3.4"}, + ServerAddress: []string{"4.3.2.1"}, + }, + }, + } + err = admindb.UpsertUser(denyUser) + c.Assert(err, IsNil) + + // Dial again to ensure the authentication restriction blocks the connections. + _, err = mgo.Dial("mongodb://denyUser:123456@127.0.0.1:40002/admin") + c.Assert(err, ErrorMatches, ".*Authentication failed.") +} + func (s *S) TestAuthAddUser(c *C) { session, err := mgo.Dial("localhost:40002") c.Assert(err, IsNil) diff --git a/session.go b/session.go index e923e774b..49beee1b9 100644 --- a/session.go +++ b/session.go @@ -1168,6 +1168,19 @@ func (s *Session) LogoutAll() { s.m.Unlock() } +// AuthenticationRestriction represents an authentication restriction +// for a MongoDB User. Authentication Restrictions was added in version +// 3.6. +// +// Relevant documentation: +// +// https://docs.mongodb.com/manual/reference/method/db.createUser/#authentication-restrictions +// +type AuthenticationRestriction struct { + ClientSource []string `bson:"clientSource,omitempty"` + ServerAddress []string `bson:"serverAddress,omitempty"` +} + // User represents a MongoDB user. // // Relevant documentation: @@ -1208,6 +1221,15 @@ type User struct { // WARNING: This setting was only ever supported in MongoDB 2.4, // and is now obsolete. UserSource string `bson:"userSource,omitempty"` + + // AuthenticationRestrictions represents authentication restrictions + // the server enforces on the created user. Specifies a list of IP + // addresses and CIDR ranges from which the user is allowed to connect + // to the server or from which the server can accept users. + // + // WARNING: Authentication Restrictions are only supported in version + // 3.6 and above. + AuthenticationRestrictions []AuthenticationRestriction `bson:"authenticationRestrictions,omitempty"` } // Role available role for users @@ -1370,6 +1392,9 @@ func (db *Database) runUserCmd(cmdName string, user *User) error { if roles != nil || user.Roles != nil || cmdName == "createUser" { cmd = append(cmd, bson.DocElem{Name: "roles", Value: roles}) } + if user.AuthenticationRestrictions != nil && len(user.AuthenticationRestrictions) > 0 { + cmd = append(cmd, bson.DocElem{Name: "authenticationRestrictions", Value: user.AuthenticationRestrictions}) + } err := db.Run(cmd, nil) if !isNoCmd(err) && user.UserSource != "" && (user.UserSource != "$external" || db.Name != "$external") { return fmt.Errorf("MongoDB 2.6+ does not support the UserSource setting")