summaryrefslogtreecommitdiff
path: root/src/mongo/db/auth
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2017-07-12 09:43:25 -0400
committerSpencer Jackson <spencer.jackson@mongodb.com>2017-07-13 17:44:29 -0400
commitacf804c56e1043a5c3e0c8953c78d35b9775f96b (patch)
tree8d4c399e5cfb3d43ac4632ae426182d51c6ba14d /src/mongo/db/auth
parente1cae24805e3e7282958ee67a01555dd6ce40039 (diff)
downloadmongo-acf804c56e1043a5c3e0c8953c78d35b9775f96b.tar.gz
SERVER-29171: Implement Restriction BSON IDL serializer/deserializer
Diffstat (limited to 'src/mongo/db/auth')
-rw-r--r--src/mongo/db/auth/SConscript6
-rw-r--r--src/mongo/db/auth/address_restriction.cpp37
-rw-r--r--src/mongo/db/auth/address_restriction.h40
-rw-r--r--src/mongo/db/auth/address_restriction.idl39
-rw-r--r--src/mongo/db/auth/address_restriction_test.cpp103
-rw-r--r--src/mongo/db/auth/restriction.h8
6 files changed, 217 insertions, 16 deletions
diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript
index 596c75d7f8b..7513bf04e1c 100644
--- a/src/mongo/db/auth/SConscript
+++ b/src/mongo/db/auth/SConscript
@@ -259,11 +259,15 @@ env.CppUnitTest(
env.Library(
target='address_restriction',
- source='address_restriction.cpp',
+ source=[
+ 'address_restriction.cpp',
+ env.Idlc('address_restriction.idl')[0],
+ ],
LIBDEPS=[
'authentication_restriction',
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/util/net/network',
+ '$BUILD_DIR/mongo/idl/idl_parser',
],
)
diff --git a/src/mongo/db/auth/address_restriction.cpp b/src/mongo/db/auth/address_restriction.cpp
index e876d34b127..8b2de7770bd 100644
--- a/src/mongo/db/auth/address_restriction.cpp
+++ b/src/mongo/db/auth/address_restriction.cpp
@@ -29,15 +29,36 @@
#include "mongo/platform/basic.h"
#include "mongo/db/auth/address_restriction.h"
+#include "mongo/db/auth/address_restriction_gen.h"
+#include "mongo/stdx/memory.h"
-namespace mongo {
-namespace address_restriction_detail {
+constexpr mongo::StringData mongo::address_restriction_detail::ClientSource::label;
+constexpr mongo::StringData mongo::address_restriction_detail::ClientSource::field;
-constexpr StringData ClientSource::label;
-constexpr StringData ClientSource::field;
+constexpr mongo::StringData mongo::address_restriction_detail::ServerAddress::label;
+constexpr mongo::StringData mongo::address_restriction_detail::ServerAddress::field;
-constexpr StringData ServerAddress::label;
-constexpr StringData ServerAddress::field;
+mongo::StatusWith<mongo::RestrictionSet<>> mongo::parseAddressRestrictionSet(
+ const BSONObj& obj) try {
+ IDLParserErrorContext ctx("address restriction");
+ const auto ar = Address_restriction::parse(ctx, obj);
+ std::vector<std::unique_ptr<Restriction>> vec;
-} // address_restriction_detail
-} // mongo
+ const boost::optional<std::vector<StringData>>& client = ar.getClientSource();
+ if (client) {
+ vec.push_back(stdx::make_unique<ClientSourceRestriction>(client.get()));
+ }
+
+ const boost::optional<std::vector<StringData>>& server = ar.getServerAddress();
+ if (server) {
+ vec.push_back(stdx::make_unique<ServerAddressRestriction>(server.get()));
+ }
+
+ if (vec.empty()) {
+ return Status(ErrorCodes::CollectionIsEmpty,
+ "At least one of 'clientSource' or 'serverAddress' must be set");
+ }
+ return RestrictionSet<>(std::move(vec));
+} catch (const DBException& e) {
+ return Status(ErrorCodes::BadValue, e.what());
+}
diff --git a/src/mongo/db/auth/address_restriction.h b/src/mongo/db/auth/address_restriction.h
index 27fd2c8259e..e4b6e4c15e4 100644
--- a/src/mongo/db/auth/address_restriction.h
+++ b/src/mongo/db/auth/address_restriction.h
@@ -33,9 +33,12 @@
#include "mongo/bson/bsonmisc.h"
#include "mongo/db/auth/restriction.h"
#include "mongo/db/auth/restriction_environment.h"
+#include "mongo/db/auth/restriction_set.h"
#include "mongo/util/net/cidr.h"
+#include <memory>
#include <string>
+#include <vector>
namespace mongo {
@@ -75,17 +78,42 @@ public:
/**
* Construct an AddressRestriction based on several human readable subnet specs
*/
- explicit AddressRestriction(const std::vector<std::string>& ranges) {
+ template <typename StringType>
+ explicit AddressRestriction(const std::vector<StringType>& ranges) {
for (auto const& range : ranges) {
_ranges.emplace_back(range);
}
}
/**
+ * If the given BSONElement represents a valid CIDR range, constructs and returns the
+ * AddressRestriction. Otherwise returns an error.
+ */
+ static StatusWith<AddressRestriction<T>> parse(BSONElement from) {
+ auto cidr = CIDR::parse(from);
+ if (!cidr.isOK()) {
+ return cidr.getStatus();
+ }
+ return AddressRestriction<T>(std::move(cidr.getValue()));
+ }
+
+ /**
+ * If the given string represents a valid CIDR range, constructs and returns the
+ * AddressRestriction. Otherwise returns an error.
+ */
+ static StatusWith<AddressRestriction<T>> parse(StringData from) {
+ auto cidr = CIDR::parse(from);
+ if (!cidr.isOK()) {
+ return cidr.getStatus();
+ }
+ return AddressRestriction<T>(std::move(cidr.getValue()));
+ }
+
+ /**
* Returns true if the Environment's client/server's address
* satisfies this restriction set.
*/
- Status validate(const RestrictionEnvironment& environment) const noexcept override {
+ Status validate(const RestrictionEnvironment& environment) const override {
auto const addr = T::addr(environment);
if (!addr.isIP()) {
std::ostringstream s;
@@ -107,7 +135,7 @@ public:
}
/**
- * Append to builder as string element with the human-readable CIDR range.
+ * Append to builder an array element with the human-readable CIDR ranges.
*/
void appendToBuilder(BSONObjBuilder* builder) const {
BSONArrayBuilder b;
@@ -150,6 +178,12 @@ using ClientSourceRestriction =
using ServerAddressRestriction =
address_restriction_detail::AddressRestriction<address_restriction_detail::ServerAddress>;
+/**
+ * Parse a set of clientSource, serverAddress, or both
+ * and return a RestrictionSet on success.
+ */
+StatusWith<RestrictionSet<>> parseAddressRestrictionSet(const BSONObj& obj);
+
template <>
inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<<ClientSourceRestriction>(
ClientSourceRestriction value) {
diff --git a/src/mongo/db/auth/address_restriction.idl b/src/mongo/db/auth/address_restriction.idl
new file mode 100644
index 00000000000..20ec9ad9618
--- /dev/null
+++ b/src/mongo/db/auth/address_restriction.idl
@@ -0,0 +1,39 @@
+# Copyright (C) 2017 MongoDB Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# This IDL file describes the BSON format for a ConnectionRestriction, and
+# handles the serialization to and deserialization from its BSON representation
+# for that class.
+
+global:
+ cpp_namespace: "mongo"
+ cpp_includes:
+ - "mongo/db/auth/address_restriction.h"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+structs:
+
+ address_restriction:
+ description: "clientSource/serverAddress restriction pair"
+ strict: true
+ fields:
+ clientSource:
+ type: array<string>
+ optional: true
+ serverAddress:
+ type: array<string>
+ optional: true
diff --git a/src/mongo/db/auth/address_restriction_test.cpp b/src/mongo/db/auth/address_restriction_test.cpp
index abfcc34b01b..380e35d8d74 100644
--- a/src/mongo/db/auth/address_restriction_test.cpp
+++ b/src/mongo/db/auth/address_restriction_test.cpp
@@ -48,7 +48,7 @@ TEST(AddressRestrictionTest, toAndFromStringSingle) {
{"169.254.0.0/16", "169.254.0.0/16"},
{"fe80::/10", "fe80::/10"},
};
- for (auto const& p : strings) {
+ for (const auto& p : strings) {
{
const ClientSourceRestriction csr(p.input);
std::ostringstream actual;
@@ -77,7 +77,7 @@ TEST(AddressRestrictionTest, toAndFromStringVector) {
{{"127.0.0.1", "169.254.0.0/16", "::1"},
"[\"127.0.0.1/32\", \"169.254.0.0/16\", \"::1/128\"]"},
};
- for (auto const& p : tests) {
+ for (const auto& p : tests) {
{
const ClientSourceRestriction csr(p.input);
std::ostringstream actual;
@@ -225,5 +225,104 @@ TEST(AddressRestrictionTest, contains) {
}
}
+TEST(AddressRestrictionTest, parseFail) {
+ const BSONObj
+ tests[] =
+ {
+ BSON("unknownField"
+ << ""),
+ BSON("clientSource"
+ << "1.2.3.4.5"),
+ BSON("clientSource"
+ << "1.2.3.4"
+ << "unknownField"
+ << ""),
+ BSON("clientSource"
+ << "1.2.3.4"
+ << "clientSource"
+ << "2.3.4.5"),
+ };
+ for (const auto& t : tests) {
+ ASSERT_FALSE(parseAddressRestrictionSet(t).isOK());
+ }
+}
+
+TEST(AddressRestrictionTest, parseAndMatch) {
+ const struct {
+ // Restriction
+ std::vector<std::string> clientSource;
+ std::vector<std::string> serverAddress;
+ // Environment
+ std::string client;
+ std::string server;
+ // Should pass validation check
+ bool valid;
+ } tests[] = {
+ {{"127.0.0.0/8"}, {"127.0.0.0/8"}, "127.0.0.1", "127.0.0.1", true},
+ {{"127.0.0.0/8"}, {"127.0.0.0/8"}, "127.0.0.1", "169.254.1.2", false},
+ {{"127.0.0.0/8"}, {"127.0.0.0/8"}, "169.254.3.4", "127.0.0.1", false},
+ {{"127.0.0.0/8"}, {"127.0.0.0/8"}, "169.254.12.34", "169.254.56.78", false},
+
+ {{"127.0.0.0/8"}, {}, "127.0.0.1", "169.254.5.6", true},
+ {{"127.0.0.0/8"}, {}, "127.0.0.1", "127.0.0.1", true},
+ {{"127.0.0.0/8"}, {}, "169.254.7.8", "127.0.0.1", false},
+ {{"127.0.0.0/8"}, {}, "169.254.9.10", "169.254.11.12", false},
+
+ {{}, {"127.0.0.0/8"}, "127.0.0.1", "169.254.5.6", false},
+ {{}, {"127.0.0.0/8"}, "127.0.0.1", "127.0.0.1", true},
+ {{}, {"127.0.0.0/8"}, "169.254.7.8", "127.0.0.1", true},
+ {{}, {"127.0.0.0/8"}, "169.254.9.10", "169.254.11.12", false},
+
+ {{"::/0"}, {"::/0"}, "127.0.0.1", "127.0.0.1", false},
+ {{"0.0.0.0/0"}, {"0.0.0.0/0"}, "::1", "::1", false},
+
+ {{"::1"}, {"::1"}, "::1", "::1", true},
+ {{"::1"}, {"::1"}, "::2", "::1", false},
+ {{"::1"}, {"::1"}, "::1", "::2", false},
+ {{"::1"}, {"::1"}, "::2", "::2", false},
+
+ {{"fe80::/10"}, {}, "fe80::dead:beef", "::1", true},
+ {{"fe80::/10"}, {}, "fe80::dead:beef", "::ffff:127.0.0.1", true},
+ {{"fe80::/10"}, {}, "fe80::dead:beef", "127.0.0.1", true},
+ {{"fe80::/10"}, {}, "fe80::dead:beef", "fe80::ba5e:ba11", true},
+
+ {{"fe80::/10"}, {}, "fec0::dead:beef", "fe80::1", false},
+ {{"fe80::/10"}, {}, "fec0::dead:beef", "fe80::1", false},
+ {{"fe80::/10"}, {}, "fec0::dead:beef", "fe80::1", false},
+ {{"fe80::/10"}, {}, "fec0::dead:beef", "fe80::1", false},
+
+ {{}, {"fe80::/10"}, "::1", "fe80::dead:beef", true},
+ {{}, {"fe80::/10"}, "::ffff:127.0.0.1", "fe80::dead:beef", true},
+ {{}, {"fe80::/10"}, "127.0.0.1", "fe80::dead:beef", true},
+ {{}, {"fe80::/10"}, "fe80::ba5e:ba11", "fe80::dead:beef", true},
+
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "::1", "fe80::1", true},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "127.0.0.1", "169.254.0.1", true},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "::1", "169.254.0.1", true},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "127.0.0.1", "fe80::1", true},
+
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "::2", "fe80::1", false},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "10.0.0.1", "169.254.0.1", false},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "::1", "192.168.0.1", false},
+ {{"127.0.0.1/8", "::1"}, {"169.254.0.0/16", "fe80::/10"}, "127.0.0.1", "fec0::1", false},
+ };
+ for (const auto& t : tests) {
+ BSONObjBuilder b;
+ if (!t.clientSource.empty()) {
+ b.append("clientSource", t.clientSource);
+ }
+ if (!t.serverAddress.empty()) {
+ b.append("serverAddress", t.serverAddress);
+ }
+ const auto doc = b.obj();
+ const auto setwith = parseAddressRestrictionSet(doc);
+ ASSERT_OK(setwith);
+
+ const RestrictionEnvironment env(SockAddr(t.client, 1024, AF_UNSPEC),
+ SockAddr(t.server, 1025, AF_UNSPEC));
+ ASSERT_EQ(setwith.getValue().validate(env).isOK(), t.valid);
+ }
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/auth/restriction.h b/src/mongo/db/auth/restriction.h
index 7e5ef56cb09..d13cd02d826 100644
--- a/src/mongo/db/auth/restriction.h
+++ b/src/mongo/db/auth/restriction.h
@@ -57,9 +57,13 @@ public:
}
friend StringBuilder& operator<<(StringBuilder& sb, const Restriction& r) {
+ return sb << r.toString();
+ }
+
+ std::string toString() const {
std::ostringstream oss;
- oss << r;
- return sb << oss.str();
+ oss << *this;
+ return oss.str();
}
private: