StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) {
    // Expecting user input on the form: user\0user\0pwd
    std::string input = inputData.toString();
    std::string pwd = "";

    try {
        _user = input.substr(0, inputData.find('\0'));
        pwd = input.substr(inputData.find('\0', _user.size() + 1) + 1);
    } catch (std::out_of_range& exception) {
        return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                mongoutils::str::stream()
                                    << "Incorrectly formatted PLAIN client message");
    }

    User* userObj;
    // The authentication database is also the source database for the user.
    Status status =
        _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser(
            _saslAuthSession->getOpCtxt(),
            UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
            &userObj);

    if (!status.isOK()) {
        return StatusWith<bool>(status);
    }

    const User::CredentialData creds = userObj->getCredentials();
    _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj);

    std::string authDigest = createPasswordDigest(_user, pwd);

    if (!creds.password.empty()) {
        // Handle schemaVersion26Final (MONGODB-CR/SCRAM mixed mode)
        if (authDigest != creds.password) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                    mongoutils::str::stream() << "Incorrect user name or password");
        }
    } else {
        // Handle schemaVersion28SCRAM (SCRAM only mode)
        unsigned char storedKey[scram::hashSize];
        unsigned char serverKey[scram::hashSize];

        scram::generateSecrets(
            authDigest,
            reinterpret_cast<const unsigned char*>(base64::decode(creds.scram.salt).c_str()),
            16,
            creds.scram.iterationCount,
            storedKey,
            serverKey);
        if (creds.scram.storedKey !=
            base64::encode(reinterpret_cast<const char*>(storedKey), scram::hashSize)) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                    mongoutils::str::stream() << "Incorrect user name or password");
        }
    }

    *outputData = "";

    return StatusWith<bool>(true);
}
Exemple #2
0
	bool DBClientConnection::auth(const string &dbname, const string &username, const string &password_text, string& errmsg, bool digestPassword) {
		string password = password_text;
		if( digestPassword ) 
			password = createPasswordDigest( username , password_text );

		if( autoReconnect ) {
			/* note we remember the auth info before we attempt to auth -- if the connection is broken, we will 
			   then have it for the next autoreconnect attempt. 
			*/
			pair<string,string> p = pair<string,string>(username, password);
			authCache[dbname] = p;
		}

		return DBClientBase::auth(dbname, username, password.c_str(), errmsg, false);
	}
Exemple #3
0
    bool DBClientWithCommands::auth(const string &dbname, const string &username, const string &password_text, string& errmsg, bool digestPassword) {
		//cout << "TEMP AUTH " << toString() << dbname << ' ' << username << ' ' << password_text << ' ' << digestPassword << endl;

		string password = password_text;
		if( digestPassword ) 
			password = createPasswordDigest( username , password_text );

        BSONObj info;
        string nonce;
        if( !runCommand(dbname, getnoncecmdobj, info) ) {
            errmsg = "getnonce fails - connection problem?";
            return false;
        }
        {
            BSONElement e = info.getField("nonce");
            assert( e.type() == String );
            nonce = e.valuestr();
        }

        BSONObj authCmd;
        BSONObjBuilder b;
        {

            b << "authenticate" << 1 << "nonce" << nonce << "user" << username;
            md5digest d;
            {
                md5_state_t st;
                md5_init(&st);
                md5_append(&st, (const md5_byte_t *) nonce.c_str(), nonce.size() );
                md5_append(&st, (const md5_byte_t *) username.data(), username.length());
                md5_append(&st, (const md5_byte_t *) password.c_str(), password.size() );
                md5_finish(&st, d);
            }
            b << "key" << digestToString( d );
            authCmd = b.done();
        }
        
        if( runCommand(dbname, authCmd, info) ) 
            return true;

        errmsg = info.toString();
        return false;
    }
    StatusWith<bool> SaslPLAINServerConversation::step(const StringData& inputData, 
                                                       std::string* outputData) {
        // Expecting user input on the form: user\0user\0pwd
        std::string input = inputData.toString();
        std::string pwd = "";
 
        try {
            _user = input.substr(0, inputData.find('\0'));
            pwd = input.substr(inputData.find('\0', _user.size()+1)+1);
        }
        catch (std::out_of_range& exception) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                mongoutils::str::stream() << "Incorrectly formatted PLAIN client message");
        }

        User* userObj;
        // The authentication database is also the source database for the user.
        Status status = _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().
                acquireUser(_saslAuthSession->getOpCtxt(),
                            UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
                            &userObj);

        if (!status.isOK()) {
            return StatusWith<bool>(status);
        }

        const User::CredentialData creds = userObj->getCredentials();
        _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().
                releaseUser(userObj);

        std::string authDigest = createPasswordDigest(_user, pwd);
 
        if (authDigest != creds.password) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                mongoutils::str::stream() << "Incorrect user name or password");
        }

        *outputData = "";

        return StatusWith<bool>(true);
    }
StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) {
    if (_saslAuthSession->getAuthenticationDatabase() == "$external") {
        return Status(ErrorCodes::AuthenticationFailed,
                      "PLAIN mechanism must be used with internal users");
    }

    // Expecting user input on the form: [authz-id]\0authn-id\0pwd
    std::string input = inputData.toString();

    SecureAllocatorAuthDomain::SecureString pwd = "";
    try {
        size_t firstNull = inputData.find('\0');
        if (firstNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing first NULL delimiter");
        }
        size_t secondNull = inputData.find('\0', firstNull + 1);
        if (secondNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing second NULL delimiter");
        }

        std::string authorizationIdentity = input.substr(0, firstNull);
        _user = input.substr(firstNull + 1, (secondNull - firstNull) - 1);
        if (_user.empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty username");
        } else if (!authorizationIdentity.empty() && authorizationIdentity != _user) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "SASL authorization identity must match authentication identity");
        }
        pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str());
        if (pwd->empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty password");
        }
    } catch (std::out_of_range& exception) {
        return Status(ErrorCodes::AuthenticationFailed,
                      mongoutils::str::stream() << "Incorrectly formatted PLAIN client message");
    }

    User* userObj;
    // The authentication database is also the source database for the user.
    Status status =
        _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser(
            _saslAuthSession->getOpCtxt(),
            UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
            &userObj);

    if (!status.isOK()) {
        return StatusWith<bool>(status);
    }

    const User::CredentialData creds = userObj->getCredentials();
    _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj);

    std::string authDigest = createPasswordDigest(_user, pwd->c_str());

    if (!creds.password.empty()) {
        // Handle schemaVersion26Final (MONGODB-CR/SCRAM mixed mode)
        if (authDigest != creds.password) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                    mongoutils::str::stream() << "Incorrect user name or password");
        }
    } else {
        // Handle schemaVersion28SCRAM (SCRAM only mode)
        std::string decodedSalt = base64::decode(creds.scram.salt);
        scram::SCRAMSecrets secrets = scram::generateSecrets(scram::SCRAMPresecrets(
            authDigest,
            std::vector<std::uint8_t>(reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()),
                                      reinterpret_cast<const std::uint8_t*>(decodedSalt.c_str()) +
                                          16),
            creds.scram.iterationCount));
        if (creds.scram.storedKey !=
            base64::encode(reinterpret_cast<const char*>(secrets->storedKey.data()),
                           secrets->storedKey.size())) {
            return StatusWith<bool>(ErrorCodes::AuthenticationFailed,
                                    mongoutils::str::stream() << "Incorrect user name or password");
        }
    }

    *outputData = "";

    return StatusWith<bool>(true);
}
StatusWith<bool> SaslPLAINServerConversation::step(StringData inputData, std::string* outputData) {
    if (_saslAuthSession->getAuthenticationDatabase() == "$external") {
        return Status(ErrorCodes::AuthenticationFailed,
                      "PLAIN mechanism must be used with internal users");
    }

    // Expecting user input on the form: [authz-id]\0authn-id\0pwd
    std::string input = inputData.toString();

    SecureAllocatorAuthDomain::SecureString pwd = "";
    try {
        size_t firstNull = inputData.find('\0');
        if (firstNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing first NULL delimiter");
        }
        size_t secondNull = inputData.find('\0', firstNull + 1);
        if (secondNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing second NULL delimiter");
        }

        std::string authorizationIdentity = input.substr(0, firstNull);
        _user = input.substr(firstNull + 1, (secondNull - firstNull) - 1);
        if (_user.empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty username");
        } else if (!authorizationIdentity.empty() && authorizationIdentity != _user) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "SASL authorization identity must match authentication identity");
        }
        pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str());
        if (pwd->empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty password");
        }
    } catch (std::out_of_range&) {
        return Status(ErrorCodes::AuthenticationFailed,
                      mongoutils::str::stream() << "Incorrectly formatted PLAIN client message");
    }

    User* userObj;
    // The authentication database is also the source database for the user.
    Status status =
        _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().acquireUser(
            _saslAuthSession->getOpCtxt(),
            UserName(_user, _saslAuthSession->getAuthenticationDatabase()),
            &userObj);

    if (!status.isOK()) {
        return status;
    }

    const auto creds = userObj->getCredentials();
    _saslAuthSession->getAuthorizationSession()->getAuthorizationManager().releaseUser(userObj);

    *outputData = "";
    const auto sha256Status = trySCRAM<SHA256Block>(creds, pwd->c_str());
    if (!sha256Status.isOK()) {
        return sha256Status;
    }
    if (sha256Status.getValue()) {
        return true;
    }

    const auto authDigest = createPasswordDigest(_user, pwd->c_str());
    const auto sha1Status = trySCRAM<SHA1Block>(creds, authDigest);
    if (!sha1Status.isOK()) {
        return sha1Status;
    }
    if (sha1Status.getValue()) {
        return true;
    }

    return Status(ErrorCodes::AuthenticationFailed, str::stream() << "No credentials available.");
}
StatusWith<std::tuple<bool, std::string>> SASLPlainServerMechanism::stepImpl(
    OperationContext* opCtx, StringData inputData) {
    if (_authenticationDatabase == "$external") {
        return Status(ErrorCodes::AuthenticationFailed,
                      "PLAIN mechanism must be used with internal users");
    }

    AuthorizationManager* authManager = AuthorizationManager::get(opCtx->getServiceContext());

    // Expecting user input on the form: [authz-id]\0authn-id\0pwd
    std::string input = inputData.toString();

    SecureAllocatorAuthDomain::SecureString pwd = "";
    try {
        size_t firstNull = inputData.find('\0');
        if (firstNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing first NULL delimiter");
        }
        size_t secondNull = inputData.find('\0', firstNull + 1);
        if (secondNull == std::string::npos) {
            return Status(
                ErrorCodes::AuthenticationFailed,
                str::stream()
                    << "Incorrectly formatted PLAIN client message, missing second NULL delimiter");
        }

        std::string authorizationIdentity = input.substr(0, firstNull);
        ServerMechanismBase::_principalName =
            input.substr(firstNull + 1, (secondNull - firstNull) - 1);
        if (ServerMechanismBase::_principalName.empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty username");
        } else if (!authorizationIdentity.empty() &&
                   authorizationIdentity != ServerMechanismBase::_principalName) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "SASL authorization identity must match authentication identity");
        }
        pwd = SecureAllocatorAuthDomain::SecureString(input.substr(secondNull + 1).c_str());
        if (pwd->empty()) {
            return Status(ErrorCodes::AuthenticationFailed,
                          str::stream()
                              << "Incorrectly formatted PLAIN client message, empty password");
        }
    } catch (std::out_of_range&) {
        return Status(ErrorCodes::AuthenticationFailed,
                      str::stream() << "Incorrectly formatted PLAIN client message");
    }

    // The authentication database is also the source database for the user.
    auto swUser = authManager->acquireUser(
        opCtx, UserName(ServerMechanismBase::_principalName, _authenticationDatabase));

    if (!swUser.isOK()) {
        return swUser.getStatus();
    }

    auto userObj = std::move(swUser.getValue());
    const auto creds = userObj->getCredentials();

    const auto sha256Status = trySCRAM<SHA256Block>(creds, pwd->c_str());
    if (!sha256Status.isOK()) {
        return sha256Status.getStatus();
    }
    if (sha256Status.getValue()) {
        return std::make_tuple(true, std::string());
    }

    const auto authDigest = createPasswordDigest(ServerMechanismBase::_principalName, pwd->c_str());
    const auto sha1Status = trySCRAM<SHA1Block>(creds, authDigest);
    if (!sha1Status.isOK()) {
        return sha1Status.getStatus();
    }
    if (sha1Status.getValue()) {
        return std::make_tuple(true, std::string());
    }

    return Status(ErrorCodes::AuthenticationFailed, str::stream() << "No credentials available.");


    return std::make_tuple(true, std::string());
}