Ejemplo n.º 1
0
bool replAuthenticate(DBClientBase* conn) {
    if (isInternalAuthSet())
        return conn->authenticateInternalUser();
    if (getGlobalAuthorizationManager()->isAuthEnabled())
        return false;
    return true;
}
Ejemplo n.º 2
0
 void setInternalUserAuthParams(const BSONObj& authParamsIn) {
     if (!isInternalAuthSet()) {
         authParamsSet = true;
     }
     boost::mutex::scoped_lock lk(authParamMutex);
     authParams = authParamsIn.copy();
 }
Ejemplo n.º 3
0
    bool isSelf(const HostAndPort& hostAndPort) {

        // Fastpath: check if the host&port in question is bound to one
        // of the interfaces on this machine.
        // No need for ip match if the ports do not match
        if (hostAndPort.port() == serverGlobalParams.port) {
            std::vector<std::string> myAddrs = serverGlobalParams.bind_ip.empty() ?
              getBoundAddrs(IPv6Enabled()) :
              std::vector<std::string>();

            if (!serverGlobalParams.bind_ip.empty()) {
                boost::split(myAddrs, serverGlobalParams.bind_ip, boost::is_any_of(", "));
            }

            const std::vector<std::string> hostAddrs = getAddrsForHost(hostAndPort.host(),
                                                                       hostAndPort.port(),
                                                                       IPv6Enabled());

            for (std::vector<std::string>::const_iterator i = myAddrs.begin();
                 i != myAddrs.end(); ++i) {
                for (std::vector<std::string>::const_iterator j = hostAddrs.begin();
                     j != hostAddrs.end(); ++j) {
                    if (*i == *j) {
                        return true;
                    }
                }
            }
        }

        if (!Listener::getTimeTracker()) {
            // this ensures we are actually running a server
            // this may return true later, so may want to retry
            return false;
        }

        try {
            DBClientConnection conn;
            std::string errmsg;
            if (!conn.connect(hostAndPort, errmsg)) {
                return false;
            }

            if (getGlobalAuthorizationManager()->isAuthEnabled() && isInternalAuthSet()) {
                if (!authenticateInternalUser(&conn)) {
                    return false;
                }
            }
            BSONObj out;
            bool ok = conn.simpleCommand("admin" , &out, "_isSelf");
            bool me = ok && out["id"].type() == jstOID && instanceId == out["id"].OID();

            return me;
        }
        catch (const std::exception& e) {
            warning() << "could't check isSelf (" << hostAndPort << ") " << e.what() << std::endl;
        }

        return false;
    }
Ejemplo n.º 4
0
    bool SyncSourceFeedback::replAuthenticate() {
        if (!getGlobalAuthorizationManager()->isAuthEnabled())
            return true;

        if (!isInternalAuthSet())
            return false;
        return authenticateInternalUser(_connection.get());
    }
Ejemplo n.º 5
0
 bool setInternalUserAuthParams(BSONObj authParams) {
     if (!isInternalAuthSet()) {
         internalSecurity.authParams = authParams.copy();
         authParamsSet = true;
         return true;
     }
     else {
         log() << "Internal auth params have already been set" << endl;
         return false;
     }
 }
Ejemplo n.º 6
0
void NetworkInterfaceASIO::_authenticate(AsyncOp* op) {
    // There is currently no way for NetworkInterfaceASIO's users to run a command
    // without going through _authenticate(). Callers may want to run certain commands,
    // such as ismasters, pre-auth. We may want to offer this choice in the future.

    // This check is sufficient to see if auth is enabled on the system,
    // and avoids creating dependencies on deeper, less accessible auth code.
    if (!isInternalAuthSet()) {
        return _runConnectionHook(op);
    }

    // We will only have a valid clientName if SSL is enabled.
    std::string clientName;
#ifdef MONGO_CONFIG_SSL
    if (getSSLManager()) {
        clientName = getSSLManager()->getSSLConfiguration().clientSubjectName;
    }
#endif

    // authenticateClient will use this to run auth-related commands over our connection.
    auto runCommandHook = [this, op](executor::RemoteCommandRequest request,
                                     auth::AuthCompletionHandler handler) {

        // SERVER-14170: Set the metadataHook to nullptr explicitly as we cannot write metadata
        // here.
        auto beginStatus = op->beginCommand(request);
        if (!beginStatus.isOK()) {
            return handler(beginStatus);
        }

        auto callAuthCompletionHandler = [this, op, handler]() {
            auto authResponse =
                op->command()->response(op, op->operationProtocol(), now(), nullptr);
            handler(authResponse);
        };

        _asyncRunCommand(op,
                         [this, op, callAuthCompletionHandler](std::error_code ec, size_t bytes) {
                             _validateAndRun(op, ec, callAuthCompletionHandler);
                         });
    };

    // This will be called when authentication has completed.
    auto authHook = [this, op](auth::AuthResponse response) {
        if (!response.isOK())
            return _completeOperation(op, response);
        return _runConnectionHook(op);
    };

    auto params = getInternalUserAuthParams();
    auth::authenticateClient(
        params, op->request().target.host(), clientName, runCommandHook, authHook);
}
Ejemplo n.º 7
0
 bool authenticateInternalUser(DBClientWithCommands* conn){
     if (!isInternalAuthSet()) {
         log() << "ERROR: No authentication params set for internal user" << endl;
         return false;
     }
     try {
         conn->auth(internalSecurity.authParams); 
         return true;
     } catch(const UserException& ex) {
         log() << "can't authenticate to " << conn->toString() << " as internal user, error: "
               << ex.what() << endl;
         return false;
     }
 }
Ejemplo n.º 8
0
    bool authenticateInternalUser(DBClientWithCommands* conn) {
        if (!isInternalAuthSet()) {
            if (!serverGlobalParams.quiet) {
                log() << "ERROR: No authentication parameters set for internal user";
            }
            return false;
        }

        try {
            conn->auth(getInternalUserAuthParamsWithFallback());
            return true;
        } catch(const UserException& ex) {
            if (!serverGlobalParams.quiet) {
                log() << "can't authenticate to " << conn->toString()
                      << " as internal user, error: "<< ex.what();
            }
            return false;
        }
    }
Ejemplo n.º 9
0
 bool authenticateInternalUser(DBClientWithCommands* conn){
     if (!isInternalAuthSet()) {
         log() << "ERROR: No authentication parameters set for internal user" << endl;
         return false;
     }
     try { 
         BSONObj outgoingAuthParams;
         {
             boost::mutex::scoped_lock lk(authParamMutex);
             outgoingAuthParams = authParams.copy();
         }                
         conn->auth(outgoingAuthParams);
         return true;
     } catch(const UserException& ex) {
         log() << "can't authenticate to " << conn->toString() << " as internal user, error: "
               << ex.what() << endl;
         return false;
     }
 }
Ejemplo n.º 10
0
    void setInternalUserAuthParams(const BSONObj& authParamsIn) {
        if (!isInternalAuthSet()) {
            authParamsSet = true;
        }
        boost::mutex::scoped_lock lk(authParamMutex);

        if (authParamsIn["mechanism"].String() != "SCRAM-SHA-1") {
            authParams = authParamsIn.copy();
            return;
        }

        // Create authParams for legacy MONGODB-CR authentication for 2.6/2.8 mixed
        // mode if applicable.
        mmb::Document fallback(authParamsIn);
        fallback.root().findFirstChildNamed("mechanism").setValueString("MONGODB-CR");

        mmb::Document doc(authParamsIn);
        mmb::Element fallbackEl = doc.makeElementObject("fallbackParams");
        fallbackEl.setValueObject(fallback.getObject());
        doc.root().pushBack(fallbackEl);
        authParams = doc.getObject().copy();
    }
Ejemplo n.º 11
0
    /* Generally replAuthenticate will only be called within system threads to fully authenticate
     * connections to other nodes in the cluster that will be used as part of internal operations.
     * If a user-initiated action results in needing to call replAuthenticate, you can call it
     * with skipAuthCheck set to false. Only do this if you are certain that the proper auth
     * checks have already run to ensure that the user is authorized to do everything that this
     * connection will be used for!
     */
    bool replAuthenticate(DBClientBase *conn, bool skipAuthCheck) {
        if(!AuthorizationManager::isAuthEnabled()) {
            return true;
        }
        if (!skipAuthCheck && !cc().getAuthorizationSession()->hasInternalAuthorization()) {
            log() << "replauthenticate: requires internal authorization, failing" << endl;
            return false;
        }

        if (isInternalAuthSet()) { 
            return authenticateInternalUser(conn); 
        }

        BSONObj user;
        {
            Client::ReadContext ctxt("local.");
            if( !Helpers::findOne("local.system.users", userReplQuery, user) ||
                    // try the first user in local
                    !Helpers::getSingleton("local.system.users", user) ) {
                log() << "replauthenticate: no user in local.system.users to use for authentication" << endl;
                return false;
            }
        }
        std::string u = user.getStringField("user");
        std::string p = user.getStringField("pwd");
        massert( 10392 , "bad user object? [1]", !u.empty());
        massert( 10393 , "bad user object? [2]", !p.empty());

        std::string err;
        if( !conn->auth("local", u.c_str(), p.c_str(), err, false) ) {
            log() << "replauthenticate: can't authenticate to master server, user:" << u << endl;
            return false;
        }

        return true;
    }
Ejemplo n.º 12
0
    ConnectionPool::ConnectionList::iterator ConnectionPool::acquireConnection(
                                                                const HostAndPort& target,
                                                                Date_t now,
                                                                Milliseconds timeout) {
        boost::unique_lock<boost::mutex> lk(_mutex);

        // Clean up connections on stale/unused hosts
        _cleanUpStaleHosts_inlock(now);

        for (HostConnectionMap::iterator hostConns;
             ((hostConns = _connections.find(target)) != _connections.end());) {

            // Clean up the requested host to remove stale/unused connections
            _cleanUpOlderThan_inlock(now, &hostConns->second);
            if (hostConns->second.empty()) {
                // prevent host from causing unnecessary cleanups
                _lastUsedHosts[hostConns->first] = kNeverTooStale;
                break;
            }

            _inUseConnections.splice(_inUseConnections.begin(),
                                     hostConns->second,
                                     hostConns->second.begin());

            const ConnectionList::iterator candidate = _inUseConnections.begin();
            lk.unlock();
            try {
                if (candidate->conn->isStillConnected()) {
                    // setSoTimeout takes a double representing the number of seconds for send and
                    // receive timeouts.  Thus, we must take count() and divide by
                    // 1000.0 to get the number of seconds with a fractional part.
                    candidate->conn->setSoTimeout(timeout.count() / 1000.0);
                    return candidate;
                }
            }
            catch (...) {
                lk.lock();
                _destroyConnection_inlock(&_inUseConnections, candidate);
                throw;
            }

            lk.lock();
            _destroyConnection_inlock(&_inUseConnections, candidate);
        }

        // No idle connection in the pool; make a new one.
        lk.unlock();
        std::auto_ptr<DBClientConnection> conn(new DBClientConnection);

        // setSoTimeout takes a double representing the number of seconds for send and receive
        // timeouts.  Thus, we must take count() and divide by 1000.0 to get the number
        // of seconds with a fractional part.
        conn->setSoTimeout(timeout.count() / 1000.0);
        std::string errmsg;
        uassert(28640,
                str::stream() << "Failed attempt to connect to "
                              << target.toString() << "; " << errmsg,
                conn->connect(target, errmsg));

        conn->port().tag |= _messagingPortTags;

        if (getGlobalAuthorizationManager()->isAuthEnabled()) {
            uassert(ErrorCodes::AuthenticationFailed,
                    "Missing credentials for authenticating as internal user",
                    isInternalAuthSet());
            conn->auth(getInternalUserAuthParamsWithFallback());
        }

        lk.lock();
        return _inUseConnections.insert(_inUseConnections.begin(),
                                        ConnectionInfo(conn.release(), now));
    }
Ejemplo n.º 13
0
ConnectionPool::ConnectionList::iterator ConnectionPool::acquireConnection(
    const HostAndPort& target, Date_t now, Milliseconds timeout) {
    stdx::unique_lock<stdx::mutex> lk(_mutex);

    // Clean up connections on stale/unused hosts
    _cleanUpStaleHosts_inlock(now);

    for (HostConnectionMap::iterator hostConns;
         (hostConns = _connections.find(target)) != _connections.end();) {
        // Clean up the requested host to remove stale/unused connections
        _cleanUpOlderThan_inlock(now, &hostConns->second);

        if (hostConns->second.empty()) {
            // prevent host from causing unnecessary cleanups
            _lastUsedHosts[hostConns->first] = kNeverTooStale;
            break;
        }

        _inUseConnections.splice(
            _inUseConnections.begin(), hostConns->second, hostConns->second.begin());

        const ConnectionList::iterator candidate = _inUseConnections.begin();
        lk.unlock();

        try {
            if (candidate->conn->isStillConnected()) {
                // setSoTimeout takes a double representing the number of seconds for send and
                // receive timeouts.  Thus, we must take count() and divide by
                // 1000.0 to get the number of seconds with a fractional part.
                candidate->conn->setSoTimeout(timeout.count() / 1000.0);
                return candidate;
            }
        } catch (...) {
            lk.lock();
            _destroyConnection_inlock(&_inUseConnections, candidate);
            throw;
        }

        lk.lock();
        _destroyConnection_inlock(&_inUseConnections, candidate);
    }

    // No idle connection in the pool; make a new one.
    lk.unlock();

    std::unique_ptr<DBClientConnection> conn(new DBClientConnection());

    // setSoTimeout takes a double representing the number of seconds for send and receive
    // timeouts.  Thus, we must take count() and divide by 1000.0 to get the number
    // of seconds with a fractional part.
    conn->setSoTimeout(timeout.count() / 1000.0);

    if (_hook) {
        uassertStatusOK(
            conn->connect(target,
                          [this, &target](const executor::RemoteCommandResponse& isMasterReply) {
                              return _hook->validateHost(target, isMasterReply);
                          }));

        auto postConnectRequest = uassertStatusOK(_hook->makeRequest(target));

        // We might not have a postConnectRequest
        if (postConnectRequest != boost::none) {
            auto start = Date_t::now();
            auto reply =
                conn->runCommandWithMetadata(postConnectRequest->dbname,
                                             postConnectRequest->cmdObj.firstElementFieldName(),
                                             postConnectRequest->metadata,
                                             postConnectRequest->cmdObj);

            auto rcr = executor::RemoteCommandResponse(reply->getCommandReply().getOwned(),
                                                       reply->getMetadata().getOwned(),
                                                       Date_t::now() - start);

            uassertStatusOK(_hook->handleReply(target, std::move(rcr)));
        }
    } else {
        uassertStatusOK(conn->connect(target));
    }

    conn->port().tag |= _messagingPortTags;

    if (getGlobalAuthorizationManager()->isAuthEnabled()) {
        uassert(ErrorCodes::AuthenticationFailed,
                "Missing credentials for authenticating as internal user",
                isInternalAuthSet());
        conn->auth(getInternalUserAuthParamsWithFallback());
    }

    lk.lock();
    return _inUseConnections.insert(_inUseConnections.begin(), ConnectionInfo(conn.release(), now));
}
Ejemplo n.º 14
0
    bool HostAndPort::isSelf() const {

        int _p = port();
        int p = _p == -1 ? ServerGlobalParams::DefaultDBPort : _p;

        string host = str::stream() << this->host() << ":" << p;

        {
            // check cache for this host
            // debatably something _could_ change, but I'm not sure right now (erh 10/14/2010)
            scoped_lock lk( isSelfCommand._cacheLock );
            map<string,bool>::const_iterator i = isSelfCommand._cache.find( host );
            if ( i != isSelfCommand._cache.end() )
                return i->second;
        }

#if !defined(_WIN32) && !defined(__sunos__)
        // on linux and os x we can do a quick check for an ip match

        // no need for ip match if the ports do not match
        if (p == serverGlobalParams.port) {
            const vector<string> myaddrs = getMyAddrs();
            const vector<string> addrs = getAllIPs(_host);

            for (vector<string>::const_iterator i=myaddrs.begin(), iend=myaddrs.end();
                 i!=iend; ++i) {
                for (vector<string>::const_iterator j=addrs.begin(), jend=addrs.end();
                     j!=jend; ++j) {
                    string a = *i;
                    string b = *j;

                    if ( a == b || ( str::startsWith( a , "127." ) &&
                                     str::startsWith( b , "127." ) )  // 127. is all loopback
                       ) {

                        // add to cache
                        scoped_lock lk( isSelfCommand._cacheLock );
                        isSelfCommand._cache[host] = true;
                        return true;
                    }
                }
            }
        }

#endif

        if ( ! Listener::getTimeTracker() ) {
            // this ensures we are actually running a server
            // this may return true later, so may want to retry
            return false;
        }

        try {
            isSelfCommand.init();
            DBClientConnection conn;
            string errmsg;
            if ( ! conn.connect( host , errmsg ) ) {
                // should this go in the cache?
                return false;
            }

            if (getGlobalAuthorizationManager()->isAuthEnabled() && isInternalAuthSet()) {
                if (!authenticateInternalUser(&conn)) {
                    return false;
                }
            }

            BSONObj out;
            bool ok = conn.simpleCommand( "admin" , &out , "_isSelf" );
            bool me = ok && out["id"].type() == jstOID && isSelfCommand._id == out["id"].OID();

            // add to cache
            scoped_lock lk( isSelfCommand._cacheLock );
            isSelfCommand._cache[host] = me;

            return me;
        }
        catch ( std::exception& e ) {
            warning() << "could't check isSelf (" << host << ") " << e.what() << endl;
        }

        return false;
    }
Ejemplo n.º 15
0
bool isSelf(const HostAndPort& hostAndPort) {
    // Fastpath: check if the host&port in question is bound to one
    // of the interfaces on this machine.
    // No need for ip match if the ports do not match
    if (hostAndPort.port() == serverGlobalParams.port) {
        std::vector<std::string> myAddrs = serverGlobalParams.bind_ip.empty()
            ? getBoundAddrs(IPv6Enabled())
            : std::vector<std::string>();

        if (!serverGlobalParams.bind_ip.empty()) {
            boost::split(myAddrs, serverGlobalParams.bind_ip, boost::is_any_of(", "));
        }

        const std::vector<std::string> hostAddrs =
            getAddrsForHost(hostAndPort.host(), hostAndPort.port(), IPv6Enabled());

        for (std::vector<std::string>::const_iterator i = myAddrs.begin(); i != myAddrs.end();
             ++i) {
            for (std::vector<std::string>::const_iterator j = hostAddrs.begin();
                 j != hostAddrs.end();
                 ++j) {
                if (*i == *j) {
                    return true;
                }
            }
        }
    }

    // Ensure that the server is up and ready to accept incoming network requests.
    const Listener* listener = Listener::getTimeTracker();
    if (!listener) {
        return false;
    }
    listener->waitUntilListening();

    try {
        DBClientConnection conn;
        conn.setSoTimeout(30);  // 30 second timeout

        // We need to avoid the isMaster call triggered by a normal connect, which would
        // cause a deadlock. 'isSelf' is called by the Replication Coordinator when validating
        // a replica set configuration document, but the 'isMaster' command requires a lock on the
        // replication coordinator to execute. As such we call we call 'connectSocketOnly', which
        // does not call 'isMaster'.
        if (!conn.connectSocketOnly(hostAndPort).isOK()) {
            return false;
        }

        if (getGlobalAuthorizationManager()->isAuthEnabled() && isInternalAuthSet()) {
            if (!conn.authenticateInternalUser()) {
                return false;
            }
        }
        BSONObj out;
        bool ok = conn.simpleCommand("admin", &out, "_isSelf");
        bool me = ok && out["id"].type() == jstOID && instanceId == out["id"].OID();

        return me;
    } catch (const std::exception& e) {
        warning() << "couldn't check isSelf (" << hostAndPort << ") " << e.what() << std::endl;
    }

    return false;
}
Ejemplo n.º 16
0
ConnectionPool::ConnectionList::iterator ConnectionPool::acquireConnection(
    const HostAndPort& target, Date_t now, Milliseconds timeout) {
    stdx::unique_lock<stdx::mutex> lk(_mutex);

    // Clean up connections on stale/unused hosts
    _cleanUpStaleHosts_inlock(now);

    for (HostConnectionMap::iterator hostConns;
         (hostConns = _connections.find(target)) != _connections.end();) {
        // Clean up the requested host to remove stale/unused connections
        _cleanUpOlderThan_inlock(now, &hostConns->second);

        if (hostConns->second.empty()) {
            // prevent host from causing unnecessary cleanups
            _lastUsedHosts[hostConns->first] = kNeverTooStale;
            break;
        }

        _inUseConnections.splice(
            _inUseConnections.begin(), hostConns->second, hostConns->second.begin());

        const ConnectionList::iterator candidate = _inUseConnections.begin();
        lk.unlock();

        try {
            if (candidate->conn->isStillConnected()) {
                // setSoTimeout takes a double representing the number of seconds for send and
                // receive timeouts.  Thus, we must express 'timeout' in milliseconds and divide by
                // 1000.0 to get the number of seconds with a fractional part.
                candidate->conn->setSoTimeout(durationCount<Milliseconds>(timeout) / 1000.0);
                return candidate;
            }
        } catch (...) {
            lk.lock();
            _destroyConnection_inlock(&_inUseConnections, candidate);
            throw;
        }

        lk.lock();
        _destroyConnection_inlock(&_inUseConnections, candidate);
    }

    // No idle connection in the pool; make a new one.
    lk.unlock();

    std::unique_ptr<DBClientConnection> conn;
    if (_hook) {
        conn.reset(new DBClientConnection(
            false,  // auto reconnect
            0,      // socket timeout
            {},     // MongoURI
            [this, target](const executor::RemoteCommandResponse& isMasterReply) {
                return _hook->validateHost(target, BSONObj(), isMasterReply);
            }));
    } else {
        conn.reset(new DBClientConnection());
    }

    // setSoTimeout takes a double representing the number of seconds for send and receive
    // timeouts.  Thus, we must express 'timeout' in milliseconds and divide by 1000.0 to get
    // the number of seconds with a fractional part.
    conn->setSoTimeout(durationCount<Milliseconds>(timeout) / 1000.0);

    uassertStatusOK(conn->connect(target, StringData()));
    conn->setTags(_messagingPortTags);

    if (isInternalAuthSet()) {
        conn->auth(getInternalUserAuthParams());
    }

    if (_hook) {
        auto postConnectRequest = uassertStatusOK(_hook->makeRequest(target));

        // We might not have a postConnectRequest
        if (postConnectRequest != boost::none) {
            auto start = Date_t::now();
            auto reply =
                conn->runCommand(OpMsgRequest::fromDBAndBody(postConnectRequest->dbname,
                                                             postConnectRequest->cmdObj,
                                                             postConnectRequest->metadata));

            auto rcr = executor::RemoteCommandResponse(reply->getCommandReply().getOwned(),
                                                       Date_t::now() - start);

            uassertStatusOK(_hook->handleReply(target, std::move(rcr)));
        }
    }

    lk.lock();
    return _inUseConnections.insert(_inUseConnections.begin(), ConnectionInfo(conn.release(), now));
}