diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2017-07-12 09:43:25 -0400 |
---|---|---|
committer | Spencer Jackson <spencer.jackson@mongodb.com> | 2017-07-13 17:44:29 -0400 |
commit | acf804c56e1043a5c3e0c8953c78d35b9775f96b (patch) | |
tree | 8d4c399e5cfb3d43ac4632ae426182d51c6ba14d /src/mongo/db/auth | |
parent | e1cae24805e3e7282958ee67a01555dd6ce40039 (diff) | |
download | mongo-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/SConscript | 6 | ||||
-rw-r--r-- | src/mongo/db/auth/address_restriction.cpp | 37 | ||||
-rw-r--r-- | src/mongo/db/auth/address_restriction.h | 40 | ||||
-rw-r--r-- | src/mongo/db/auth/address_restriction.idl | 39 | ||||
-rw-r--r-- | src/mongo/db/auth/address_restriction_test.cpp | 103 | ||||
-rw-r--r-- | src/mongo/db/auth/restriction.h | 8 |
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: |