CVE-2023-50257 (C, published 2024-02-19T20:15Z)
Description: value: eProsima Fast DDS (formerly Fast RTPS) is a C++ implementation of the Data Distribution Service standard of the Object Management Group. Even with the application of SROS2, due to the issue where the data (`p[UD]`) and `guid` values used to disconnect between nodes are not encrypted, a vulnerability has been discovered where a malicious attacker can forcibly disconnect a Subscriber and can deny a Subscriber attempting to connect. Afterwards, if the attacker sends the packet for disconnecting, which is data (`p[UD]`), to the Global Data Space (`239.255.0.1:7400`) using the said Publisher ID, all the Subscribers (Listeners) connected to the Publisher (Talker) will not receive any data and their connection will be disconnected. Moreover, if this disconnection packet is sent continuously, the Subscribers (Listeners) trying to connect will not be able to do so. Since the initial commit of the `SecurityManager.cpp` code (`init`, `on_process_handshake`) on Nov 8, 2016, the Disconnect Vulnerability in RTPS Packets Used by SROS2 has been present prior to versions 2.13.0, 2.12.2, 2.11.3, 2.10.3, and 2.6.7.
Severity: nan (CVSS v3 base score: )
Weakness: CWE-284 \u2014 Improper Access Control
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
Repository: https://github.com/eProsima/Fast-DDS
Files changed:
include/fastrtps/rtps/security/authentication/Authentication.h
include/fastrtps/rtps/writer/ReaderProxy.h
src/cpp/CMakeLists.txt
src/cpp/rtps/participant/RTPSParticipantImpl.cpp
src/cpp/rtps/participant/RTPSParticipantImpl.h
src/cpp/rtps/security/SecurityManager.cpp
src/cpp/rtps/security/SecurityManager.h
src/cpp/security/authentication/PKIDH.cpp
src/cpp/security/authentication/PKIDH.h
test/CMakeLists.txt
test/mock/rtps/RTPSParticipantImpl/rtps/participant/RTPSParticipantImpl.h
test/mock/rtps/RTPSReader/fastrtps/rtps/reader/RTPSReader.h
test/mock/rtps/RTPSWriter/fastrtps/rtps/writer/RTPSWriter.h
test/mock/rtps/ReaderHistory/fastrtps/rtps/history/ReaderHistory.h
test/mock/rtps/SecurityPluginFactory/MockAuthenticationPlugin.h
test/mock/rtps/SecurityPluginFactory/SecurityPluginFactory.cpp
test/mock/rtps/SecurityPluginFactory/SecurityPluginFactory.h
test/mock/rtps/StatelessReader/fastrtps/rtps/reader/StatelessReader.h
test/mock/rtps/StatelessWriter/fastrtps/rtps/writer/StatelessWriter.h
test/mock/rtps/WriterHistory/fastrtps/rtps/history/WriterHistory.h
test/unittest/rtps/security/CMakeLists.txt
test/unittest/rtps/security/SecurityAuthenticationTests.cpp
test/unittest/security/authentication/BuiltinPKIDHTests.cpp
Commit message: Refs #1811. WIP SecurityManager.


Vulnerable code:
                const GUID_t remote_participant_key,
#include <unordered_map>
        RTPSParticipantListener* plisten):	m_att(PParam), m_guid(guidP,c_EntityId_RTPSParticipant),
const RTPSParticipantAttributes& RTPSParticipantImpl::getRTPSParticipantAttributes() const
{
    return this->m_att;
}

 * @file RTPSParticipant.h
        inline const GUID_t& getGuid() const {return m_guid;};
        const GUID_t m_guid;
        const RTPSParticipantAttributes& getRTPSParticipantAttributes() const;
using namespace eprosima::fastrtps::rtps::security;
SecurityManager::SecurityManager()
        SecurityManager();
        const GUID_t remote_participant_key,
                const GUID_t remote_participant_key,


Fixed code:
                const GUID_t& remote_participant_key,
            $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/cpp>
            $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/cpp>
        $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/cpp>
        RTPSParticipantListener* plisten):	m_att(PParam), m_guid(guidP ,c_EntityId_RTPSParticipant),
 * @file RTPSParticipantImpl.h
        inline const GUID_t& getGuid() const { return m_guid; }

        void setGuid(GUID_t& guid) { m_guid = guid; }
        GUID_t m_guid;
        const RTPSParticipantAttributes& getRTPSParticipantAttributes() const
        {
            return this->m_att;
        }
#include <fastrtps/log/Log.h>
#include <rtps/participant/RTPSParticipantImpl.h>
#include <fastrtps/rtps/writer/StatelessWriter.h>
#include <fastrtps/rtps/reader/StatelessReader.h>
#include <fastrtps/rtps/history/WriterHistory.h>
#include <fastrtps/rtps/history/ReaderHistory.h>
#include <fastrtps/rtps/attributes/HistoryAttributes.h>
#include <cassert>
#include <thread>

#define ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_WRITER  0x000201C2
#define ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_READER  0x000201C7

const EntityId_t participant_stateless_message_writer_entity_id = ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_WRITER;
const EntityId_t participant_stateless_message_reader_entity_id = ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_READER;

using namespace eprosima::fastrtps;
using namespace ::rtps;
using namespace ::security;

bool usleep_bool()
{
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    return true;
}

SecurityManager::SecurityManager(RTPSParticipantImpl *participant) : participant_(participant),
    participant_stateless_message_writer_(nullptr),
    participant_stateless_message_writer_history_(nullptr),
    participant_stateless_message_reader_(nullptr),
    participant_stateless_message_reader_history_(nullptr),
    authentication_plugin_(nullptr)
{
    assert(participant != nullptr);
}

SecurityManager::~SecurityManager()
{
    if(authentication_plugin_ != nullptr)
        delete authentication_plugin_;
}

bool SecurityManager::init()
{
    SecurityException exception;

    authentication_plugin_ = factory_.create_authentication_plugin(participant_->getRTPSParticipantAttributes().properties);

    if(authentication_plugin_ != nullptr)
    {
        // Validate local participant
        GUID_t adjusted_participant_key;
        ValidationResult_t ret = VALIDATION_FAILED;
        
        do
        {
            ret = authentication_plugin_->validate_local_identity(&local_identity_handle_,
                adjusted_participant_key,
                participant_->getRTPSParticipantAttributes().builtin.domainId,
                participant_->getRTPSParticipantAttributes(),
                participant_->getGuid(),
                exception);
        } while(ret == VALIDATION_PENDING_RETRY && usleep_bool());

        if(ret == VALIDATION_OK)
        {
            assert(local_identity_handle_ != nullptr);

            // Create RTPS entities
            if(create_entities())
            {
                return true;
            }
        }

        delete authentication_plugin_;
        authentication_plugin_ = nullptr;
    }
    else
    {
        logInfo(SECURITY, "Authentication plugin not configured. Security will be disable");
    }

    return false;
}

void SecurityManager::remove_discovered_participant_info(const GUID_t remote_participant_key)
{
    std::unique_lock<std::mutex> lock(mutex_);
    auto dp_it = discovered_participants_.find(remote_participant_key);

    if(dp_it != discovered_participants_.end())
    {
        IdentityHandle* identity_handle = dp_it->second.get_identity_handle();

        if(identity_handle != nullptr)
        {
            SecurityException exception;
            authentication_plugin_->return_identity_handle(identity_handle, exception);
        }

        discovered_participants_.erase(dp_it);
    }
}

void SecurityManager::restore_remote_identity_handle(const GUID_t& remote_participant_key,
        IdentityHandle* remote_identity_handle)
{
    SecurityException exception;

    std::unique_lock<std::mutex> lock(mutex_);
    auto dp_it = discovered_participants_.find(remote_participant_key);

    if(dp_it != discovered_participants_.end())
    {
        assert(dp_it->second.is_identity_handle_null());
        dp_it->second.set_identity_handle(remote_identity_handle);
    }
    else
        authentication_plugin_->return_identity_handle(remote_identity_handle, exception);
}

bool SecurityManager::discovered_participant(IdentityToken&& remote_identity_token,
        const GUID_t& remote_participant_key)
    IdentityHandle* remote_identity_handle = nullptr;
    SecurityException exception;
    AuthenticationStatus auth_status = AUTHENTICATION_INIT;

    // Find information
    mutex_.lock();
    auto dp_it = discovered_participants_.find(remote_participant_key);

    if(dp_it == discovered_participants_.end())
    {
        discovered_participants_.emplace(remote_participant_key, auth_status);

        mutex_.unlock();

        // Validate remote participant.
        ValidationResult_t validation_ret = authentication_plugin_->validate_remote_identity(&remote_identity_handle,
                *local_identity_handle_, std::move(remote_identity_token),
                remote_participant_key, exception);

        switch(validation_ret)
        {
            case VALIDATION_OK:
                assert(remote_identity_handle != nullptr);
                auth_status = AUTHENTICATION_OK;
                break;
            case VALIDATION_PENDING_HANDSHAKE_REQUEST:
                assert(remote_identity_handle != nullptr);
                auth_status = AUTHENTICATION_REQUEST_NOT_SEND;
                break;
            case VALIDATION_PENDING_HANDSHAKE_MESSAGE:
                assert(remote_identity_handle != nullptr);
                auth_status = AUTHENTICATION_WAITING_REQUEST;
                break;
            case VALIDATION_PENDING_RETRY:
                // TODO(Ricardo) Send event.
            default:
                remove_discovered_participant_info(remote_participant_key);
                return false;
        };

        // Store remote handle.
        mutex_.lock();
        dp_it = discovered_participants_.find(remote_participant_key);
        if(dp_it != discovered_participants_.end())
        {
            dp_it->second.set_auth_status(auth_status);
            bool ret = dp_it->second.set_identity_handle(remote_identity_handle);
            (void)ret; assert(ret);
            remote_identity_handle = nullptr;
        }
        else
        {
            mutex_.unlock();
            authentication_plugin_->return_identity_handle(remote_identity_handle, exception); // TODO(Ricardo) Check error.
            return false;
        }
    }
    else
    {
        auth_status = dp_it->second.get_auth_status();

        if(auth_status == AUTHENTICATION_INIT)
            return false;
    }

    if(auth_status == AUTHENTICATION_REQUEST_NOT_SEND)
    {
        remote_identity_handle = dp_it->second.get_identity_handle();
        assert(remote_identity_handle);
    }
    mutex_.unlock();

    bool returnedValue = true;

    // Maybe send request.
    if(remote_identity_handle != nullptr)
    {
        returnedValue = on_request_not_send(remote_participant_key, remote_identity_handle);
    }

    return returnedValue;
}

bool SecurityManager::on_request_not_send(const GUID_t& remote_participant_key,
        IdentityHandle* remote_identity_handle)
{
    assert(remote_identity_handle);

    HandshakeHandle* handshake_handle = nullptr;
    HandshakeMessageToken* handshake_message = nullptr;
    SecurityException exception;
    
    ValidationResult_t ret = authentication_plugin_->begin_handshake_request(&handshake_handle,
                &handshake_message,
                *local_identity_handle_,
                *remote_identity_handle,
                exception);

    if(ret == VALIDATION_FAILED)
    {
        restore_remote_identity_handle(remote_participant_key, remote_identity_handle);
        return false;
    }

    assert(handshake_handle);
    assert(handshake_message);

    // Send hanshake message
    // 
    delete handshake_message;

    AuthenticationStatus auth_status = AUTHENTICATION_FAILED;

    switch(ret)
    {
        case VALIDATION_OK:
            auth_status = AUTHENTICATION_OK;
            break;
        case VALIDATION_PENDING_HANDSHAKE_MESSAGE:
            auth_status = AUTHENTICATION_WAITING_REPLY;
            break;
        case VALIDATION_OK_WITH_FINAL_MESSAGE:
            auth_status = AUTHENTICATION_OK;
            break;
        case VALIDATION_PENDING_RETRY:
            // TODO(Ricardo) Send event.
        default:
            restore_remote_identity_handle(remote_participant_key, remote_identity_handle);
            return false;
    };

    // Store status
    std::unique_lock<std::mutex> lock(mutex_);

    auto dp_it = discovered_participants_.find(remote_participant_key);

    if(dp_it != discovered_participants_.end())
    {
        assert(dp_it->second.get_auth_status() == AUTHENTICATION_REQUEST_NOT_SEND);
        dp_it->second.set_auth_status(auth_status);
        assert(dp_it->second.is_identity_handle_null());
        dp_it->second.set_identity_handle(remote_identity_handle);
        assert(dp_it->second.is_handshake_handle_null());
        dp_it->second.set_handshake_handle(handshake_handle);
    }
    else
    {
        authentication_plugin_->return_handshake_handle(handshake_handle, exception);
        authentication_plugin_->return_identity_handle(remote_identity_handle, exception);
        return false;
    }

    return true;
}

bool SecurityManager::create_entities()
{
    if(create_participant_stateless_message_entities())
    {
        return true;
    }

    return false; 
}

bool SecurityManager::create_participant_stateless_message_entities()
{
    if(create_participant_stateless_message_writer())
    {
        if(create_participant_stateless_message_reader())
        {
            return true;
        }

        delete_participant_stateless_message_writer();
    }

    return false;
}

void SecurityManager::delete_participant_stateless_message_entities()
{
    delete_participant_stateless_message_reader();
    delete_participant_stateless_message_writer();
}

bool SecurityManager::create_participant_stateless_message_writer()
{
    HistoryAttributes hatt;
    hatt.payloadMaxSize = 5000;
    hatt.initialReservedCaches = 20;
    hatt.maximumReservedCaches = 100;
    participant_stateless_message_writer_history_ = new WriterHistory(hatt);
    WriterAttributes watt;
    watt.endpoint.endpointKind = WRITER;
    watt.endpoint.reliabilityKind = BEST_EFFORT;
    watt.endpoint.topicKind = NO_KEY;

    if(participant_->getRTPSParticipantAttributes().throughputController.bytesPerPeriod != UINT32_MAX &&
            participant_->getRTPSParticipantAttributes().throughputController.periodMillisecs != 0)
        watt.mode = ASYNCHRONOUS_WRITER;

    RTPSWriter* wout = nullptr;
    if(participant_->createWriter(&wout, watt, participant_stateless_message_writer_history_, nullptr, participant_stateless_message_writer_entity_id, true))
    {
        participant_stateless_message_writer_ = dynamic_cast<StatelessWriter*>(wout);

        return true;
    }

    logError(SECURITY,"Participant Stateless Message Writer creation failed");
    delete(participant_stateless_message_writer_history_);
    participant_stateless_message_writer_history_ = nullptr;

    return false;
}

void SecurityManager::delete_participant_stateless_message_writer()
{
    if(participant_stateless_message_writer_ != nullptr)
        delete participant_stateless_message_writer_;

    if(participant_stateless_message_writer_history_ != nullptr)
        delete participant_stateless_message_writer_history_;
}

bool SecurityManager::create_participant_stateless_message_reader()
{
    HistoryAttributes hatt;
    hatt.payloadMaxSize = 5000;
    hatt.initialReservedCaches = 250;
    hatt.maximumReservedCaches = 5000;
    participant_stateless_message_reader_history_ = new ReaderHistory(hatt);
    ReaderAttributes ratt;
    ratt.endpoint.topicKind = NO_KEY;
    ratt.endpoint.reliabilityKind = BEST_EFFORT;
    //mp_listener = new PDPSimpleListener(this);

    RTPSReader* rout = nullptr;
    if(participant_->createReader(&rout, ratt, participant_stateless_message_reader_history_, nullptr, participant_stateless_message_reader_entity_id, true, false))
    {
        participant_stateless_message_reader_ = dynamic_cast<StatelessReader*>(rout);

        return true;
    }

    logError(SECURITY,"Participant Stateless Message Reader creation failed");
    delete(participant_stateless_message_reader_history_);
    participant_stateless_message_reader_history_ = nullptr;
    //delete(mp_listener);
    //mp_listener = nullptr;
    return false;
}

void SecurityManager::delete_participant_stateless_message_reader()
{
    if(participant_stateless_message_reader_ != nullptr)
        delete participant_stateless_message_reader_;

    if(participant_stateless_message_reader_history_ != nullptr)
        delete participant_stateless_message_reader_history_;
#include "SecurityPluginFactory.h"

#include <fastrtps/rtps/security/authentication/Handshake.h>

#include <map>
#include <mutex>


class RTPSParticipantImpl;
class StatelessWriter;
class StatelessReader;
class WriterHistory;
class ReaderHistory;

class Authentication;
        SecurityManager(RTPSParticipantImpl* participant);

        ~SecurityManager();

        bool init();

        bool discovered_participant(IdentityToken&& remote_identity_token,
                const GUID_t& remote_participant_key);

    private:

        enum AuthenticationStatus : uint32_t
        {
            AUTHENTICATION_OK = 0,
            AUTHENTICATION_FAILED,
            AUTHENTICATION_INIT,
            AUTHENTICATION_REQUEST_NOT_SEND,
            AUTHENTICATION_WAITING_REQUEST,
            AUTHENTICATION_WAITING_REPLY,
            AUTHENTICATION_WAITING_FINAL
        };

        class DiscoveredParticipantInfo
        {
            public:

                DiscoveredParticipantInfo(AuthenticationStatus auth_status) :
                    identity_handle_(nullptr), handshake_handle_(nullptr),
                    auth_status_(auth_status){}

                bool is_identity_handle_null()
                {
                    return identity_handle_ == nullptr;
                }

                bool set_identity_handle(IdentityHandle* identity_handle)
                {
                    if(identity_handle_ == nullptr)
                    {
                        identity_handle_ = identity_handle;
                        return true;
                    }

                    return false;
                }

                IdentityHandle* get_identity_handle()
                {
                    IdentityHandle* handle = identity_handle_;
                    identity_handle_ = nullptr;
                    return handle;
                }

                bool is_handshake_handle_null()
                {
                    return handshake_handle_ == nullptr;
                }

                bool set_handshake_handle(HandshakeHandle* handshake_handle)
                {
                    if(handshake_handle_ == nullptr)
                    {
                        handshake_handle_ = handshake_handle;
                        return true;
                    }

                    return false;
                }

                HandshakeHandle* get_handshake_handle()
                {
                    HandshakeHandle* handle = handshake_handle_;
                    handshake_handle_ = nullptr;
                    return handle;
                }

                AuthenticationStatus get_auth_status()
                {
                    return auth_status_;
                }

                void set_auth_status(AuthenticationStatus auth_status)
                {
                    auth_status_ = auth_status;
                }

            private:

                DiscoveredParticipantInfo(const DiscoveredParticipantInfo& info) = delete;

                IdentityHandle* identity_handle_;

                HandshakeHandle* handshake_handle_;

                AuthenticationStatus auth_status_;
        };

        void remove_discovered_participant_info(const GUID_t remote_participant_key);
        void restore_remote_identity_handle(const GUID_t& remote_participant_key,
                IdentityHandle* remote_identity_handle);

        bool create_entities();
        void delete_entities();
        bool create_participant_stateless_message_entities();
        void delete_participant_stateless_message_entities();
        bool create_participant_stateless_message_writer();
        void delete_participant_stateless_message_writer();
        bool create_participant_stateless_message_reader();
        void delete_participant_stateless_message_reader();

        bool on_request_not_send(const GUID_t& remote_participant_key, IdentityHandle* remote_identity_handle);

        RTPSParticipantImpl* participant_;
        StatelessWriter* participant_stateless_message_writer_;
        WriterHistory* participant_stateless_message_writer_history_;
        StatelessReader* participant_stateless_message_reader_;
        ReaderHistory* participant_stateless_message_reader_history_;
        SecurityPluginFactory factory_;

        Authentication* authentication_plugin_;

        IdentityHandle* local_identity_handle_;

        std::map<GUID_t, DiscoveredParticipantInfo> discovered_participants_;

        std::mutex mutex_;
        const GUID_t& remote_participant_key,
                const GUID_t& remote_participant_key,
add_subdirectory(unittest/rtps/security)
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file RTPSParticipantImpl.h
 */

#ifndef RTPS_PARTICIPANT_RTPSPARTICIPANTIMPL_H_
#define RTPS_PARTICIPANT_RTPSPARTICIPANTIMPL_H_

#include <fastrtps/rtps/attributes/WriterAttributes.h>
#include <fastrtps/rtps/attributes/ReaderAttributes.h>

#include <gmock/gmock.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class RTPSWriter;
class RTPSReader;
class WriterHistory;
class ReaderHistory;
class WriterListener;
class ReaderListener;
class EntityId_t;

class RTPSParticipantImpl
{
    public:

        MOCK_CONST_METHOD0(getRTPSParticipantAttributes, const RTPSParticipantAttributes&());

        MOCK_CONST_METHOD0(getGuid, const GUID_t&());

        MOCK_METHOD6(createWriter, bool (RTPSWriter** Writer, WriterAttributes& param, WriterHistory* hist,WriterListener* listen,
                const EntityId_t& entityId, bool isBuiltin));

        MOCK_METHOD7(createReader, bool (RTPSReader** Reader, ReaderAttributes& param, ReaderHistory* hist,ReaderListener* listen,
                const EntityId_t& entityId, bool isBuiltin, bool enable));
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // RTPS_PARTICIPANT_RTPSPARTICIPANTIMPL_H_

// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file RTPSReader.h
 */

#ifndef _RTPS_READER_RTPSREADER_H_
#define _RTPS_READER_RTPSREADER_H_

namespace eprosima {
namespace fastrtps {
namespace rtps {

class RTPSReader
{
    public:

        virtual bool matched_writer_add(RemoteWriterAttributes& wdata) = 0;

        virtual bool matched_writer_remove(RemoteWriterAttributes& wdata) = 0;
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_READER_RTPSREADER_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file RTPSWriter.h
 */

#ifndef _RTPS_WRITER_RTPSWRITER_H_
#define _RTPS_WRITER_RTPSWRITER_H_

namespace eprosima {
namespace fastrtps {
namespace rtps {

class RTPSWriter
{
    public:

        virtual bool matched_reader_add(RemoteReaderAttributes& ratt) = 0;

        virtual bool matched_reader_remove(RemoteReaderAttributes& ratt) = 0;
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_WRITER_RTPSWRITER_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file ReaderHistory.h
 */

#ifndef _RTPS_HISTORY_READERHISTORY_H_
#define _RTPS_HISTORY_READERHISTORY_H_

#include <fastrtps/rtps/attributes/HistoryAttributes.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class ReaderHistory
{
    public:

        ReaderHistory(const HistoryAttributes& /*att*/){}
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_HISTORY_READERHISTORY_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
 * @file MockAuthenticationPlugin.h
 */

#ifndef _SECURITY_MOCKAUTHENTICATIONPLUGIN_H_
#define _SECURITY_MOCKAUTHENTICATIONPLUGIN_H_

// TODO(Ricardo) Change when GMock supports r-values.

#include <fastrtps/rtps/security/authentication/Authentication.h>
#include <gmock/gmock.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {
namespace security {

class MockAuthenticationPlugin : public Authentication
{
    public:

        MOCK_METHOD6(validate_local_identity, ValidationResult_t(IdentityHandle** local_identity_handle,
                GUID_t& adjusted_participant_key,
                const uint32_t domain_id,
                const RTPSParticipantAttributes& participant_attr,
                const GUID_t& candidate_participant_key,
                SecurityException& exception));

        MOCK_METHOD5(validate_remote_identity_rvr, ValidationResult_t(IdentityHandle** remote_identity_handle,
                const IdentityHandle& local_identity_handle,
                IdentityToken remote_identity_token,
                const GUID_t& remote_participant_key,
                SecurityException& exception));

        MOCK_METHOD5(begin_handshake_request, ValidationResult_t(HandshakeHandle** handshake_handle,
                HandshakeMessageToken** handshake_message,
                const IdentityHandle& initiator_identity_handle,
                IdentityHandle& replier_identity_handle,
                SecurityException& exception));

        MOCK_METHOD6(begin_handshake_reply_rvr, ValidationResult_t(HandshakeHandle** handshake_handle,
                HandshakeMessageToken** handshake_message_out,
                HandshakeMessageToken handshake_message_in,
                IdentityHandle& initiator_identity_handle,
                const IdentityHandle& replier_identity_handle,
                SecurityException& exception));

        MOCK_METHOD4(process_handshake_rvr, ValidationResult_t(HandshakeMessageToken** handshake_message_out,
                HandshakeMessageToken handshake_message_in,
                HandshakeHandle& handshake_handle,
                SecurityException& exception));

        MOCK_METHOD2(get_shared_secret, SharedSecretHandle*(const HandshakeHandle& handshake_handle,
                SecurityException& exception));

        MOCK_METHOD2(set_listener, bool(AuthenticationListener* listener,
                SecurityException& exception));

        MOCK_METHOD3(get_identity_token, bool(IdentityToken** identity_token,
                const IdentityHandle& handle,
                SecurityException& exception));

        MOCK_METHOD2(return_identity_token, bool(IdentityToken* token,
                SecurityException& exception));

        MOCK_METHOD2(return_handshake_handle, bool(HandshakeHandle* handshake_handle,
                SecurityException& exception));

        MOCK_METHOD2(return_identity_handle, bool(IdentityHandle* identity_handle,
                SecurityException& exception));

        MOCK_METHOD2(return_sharedsecret_handle, bool(SharedSecretHandle* sharedsecret_handle,
                SecurityException& exception));

        ValidationResult_t validate_remote_identity(IdentityHandle** remote_identity_handle,
                const IdentityHandle& local_identity_handle,
                IdentityToken&& remote_identity_token,
                const GUID_t& remote_participant_key,
                SecurityException& exception)
        {
            return validate_remote_identity_rvr(remote_identity_handle, local_identity_handle,
                    remote_identity_token, remote_participant_key, exception);
        }

        ValidationResult_t begin_handshake_reply(HandshakeHandle** handshake_handle,
                HandshakeMessageToken** handshake_message_out,
                HandshakeMessageToken&& handshake_message_in,
                IdentityHandle& initiator_identity_handle,
                const IdentityHandle& replier_identity_handle,
                SecurityException& exception)
        {
            return begin_handshake_reply_rvr(handshake_handle, handshake_message_out, handshake_message_in,
                    initiator_identity_handle, replier_identity_handle, exception);
        }

        ValidationResult_t process_handshake(HandshakeMessageToken** handshake_message_out,
                HandshakeMessageToken&& handshake_message_in,
                HandshakeHandle& handshake_handle,
                SecurityException& exception)
        {
            return process_handshake_rvr(handshake_message_out, handshake_message_in,
                    handshake_handle, exception);
        }
};

} // namespace security
} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _SECURITY_MOCKAUTHENTICATIONPLUGIN_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
 * @file SecurityPluginFactory.cpp
 */

#include "SecurityPluginFactory.h"

using namespace eprosima::fastrtps::rtps;
using namespace ::security;

Authentication* SecurityPluginFactory::auth_plugin_ = nullptr;

Authentication* SecurityPluginFactory::create_authentication_plugin(const PropertyPolicy& /*property_policy*/)
{
    return auth_plugin_;
}

void SecurityPluginFactory::set_auth_plugin(Authentication* plugin)
{
    auth_plugin_ = plugin;
}

void SecurityPluginFactory::release_auth_plugin()
{
    auth_plugin_ = nullptr;
}
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*!
 * @file SecurityPluginFactory.h
 */
#ifndef _RTPS_SECURITY_SECURITYPLUGINFACTORY_H_
#define _RTPS_SECURITY_SECURITYPLUGINFACTORY_H_

#include <fastrtps/rtps/security/authentication/Authentication.h>
#include <fastrtps/rtps/attributes/PropertyPolicy.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {
namespace security {

class SecurityPluginFactory
{
    public:

        /*!
         * @brief Create an Authentication plugin  described in the PropertyPolicy.
         * @param property_policy PropertyPolicy containing the definition of the Authentication
         * plugin that has to be created.
         * @param Pointer to the new Authentication plugin. In case of error nullptr will be returned.
         */
        Authentication* create_authentication_plugin(const PropertyPolicy& property_policy);

        static void set_auth_plugin(Authentication* plugin);

        static void release_auth_plugin();

    private:

        static Authentication* auth_plugin_;
};

} //namespace security
} //namespace rtps
} //namespace fastrtps
} //namespace eprosima

#endif // _RTPS_SECURITY_SECURITYPLUGINFACTORY_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file StatelessReader.h
 */

#ifndef _RTPS_READER_STATELESSREADER_H_
#define _RTPS_READER_STATELESSREADER_H_

#include <fastrtps/rtps/reader/RTPSReader.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class StatelessReader : public RTPSReader
{
    public:

        MOCK_METHOD1(matched_writer_add, bool(RemoteWriterAttributes&));

        MOCK_METHOD1(matched_writer_remove, bool(RemoteWriterAttributes&));
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_READER_STATELESSREADER_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file StatelessWriter.h
 */

#ifndef _RTPS_WRITER_STATELESSWRITER_H_
#define _RTPS_WRITER_STATELESSWRITER_H_

#include <fastrtps/rtps/writer/RTPSWriter.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class StatelessWriter : public RTPSWriter
{
    public:

        MOCK_METHOD1(matched_reader_add, bool(RemoteReaderAttributes&));

        MOCK_METHOD1(matched_reader_remove, bool(RemoteReaderAttributes&));
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_WRITER_STATELESSWRITER_H_
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file WriterHistory.h
 */

#ifndef _RTPS_HISTORY_WRITERHISTORY_H_
#define _RTPS_HISTORY_WRITERHISTORY_H_

#include <fastrtps/rtps/attributes/HistoryAttributes.h>

namespace eprosima {
namespace fastrtps {
namespace rtps {

class WriterHistory
{
    public:


        WriterHistory(const HistoryAttributes& /*att*/){}
};

} // namespace rtps
} // namespace fastrtps
} // namespace eprosima

#endif // _RTPS_HISTORY_WRITERHISTORY_H_
# Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

if(NOT ((MSVC OR MSVC_IDE) AND EPROSIMA_INSTALLER))
    include(${PROJECT_SOURCE_DIR}/cmake/dev/gtest.cmake)
    check_gtest()
    check_gmock()

    if(GTEST_FOUND AND GMOCK_FOUND)
        if(WIN32)
            add_definitions(-D_WIN32_WINNT=0x0601)
        endif()

        set(SOURCES_SECURITY_TEST_SOURCE
            ${PROJECT_SOURCE_DIR}/src/cpp/log/Log.cpp
            ${PROJECT_SOURCE_DIR}/src/cpp/log/StdoutConsumer.cpp
            ${PROJECT_SOURCE_DIR}/src/cpp/rtps/attributes/PropertyPolicy.cpp
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/SecurityPluginFactory/SecurityPluginFactory.cpp
            ${PROJECT_SOURCE_DIR}/src/cpp/rtps/security/SecurityManager.cpp
            ${PROJECT_SOURCE_DIR}/src/cpp/rtps/exceptions/Exception.cpp
            ${PROJECT_SOURCE_DIR}/src/cpp/rtps/security/exceptions/SecurityException.cpp
            )

        add_executable(SecurityAuthentication ${SOURCES_SECURITY_TEST_SOURCE}
            ${CMAKE_CURRENT_SOURCE_DIR}/SecurityAuthenticationTests.cpp)
        add_gtest(SecurityAuthentication 
            ${CMAKE_CURRENT_SOURCE_DIR}/SecurityAuthenticationTests.cpp)
        target_include_directories(SecurityAuthentication PRIVATE
            ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS}
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/SecurityPluginFactory
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/RTPSParticipantImpl
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/RTPSWriter
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/StatelessWriter
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/WriterHistory
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/RTPSReader
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/StatelessReader
            ${PROJECT_SOURCE_DIR}/test/mock/rtps/ReaderHistory
            ${PROJECT_SOURCE_DIR}/src/cpp/rtps/security
            ${PROJECT_SOURCE_DIR}/include ${PROJECT_BINARY_DIR}/include/${PROJECT_NAME})
        target_link_libraries(SecurityAuthentication ${Boost_LIBRARIES} ${GMOCK_LIBRARIES})
    endif()
endif()
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <fastrtps/rtps/security/common/Handle.h>
#include <MockAuthenticationPlugin.h>
#include <rtps/participant/RTPSParticipantImpl.h>
#include <SecurityPluginFactory.h>
#include <SecurityManager.h>

#include <gtest/gtest.h>

using namespace eprosima::fastrtps::rtps;
using namespace ::security;
using namespace ::testing;

using ::testing::DefaultValue;

class MockIdentity
{
    public:

        static const char* const class_id_;
};

const char* const MockIdentity::class_id_ = "MockIdentityHandle";

typedef HandleImpl<MockIdentity> MockIdentityHandle;

class MockHandshake
{
    public:

        static const char* const class_id_;
};

const char* const MockHandshake::class_id_ = "MockHandshakeHandle";

typedef HandleImpl<MockHandshake> MockHandshakeHandle;

// Default Values
RTPSParticipantAttributes pattr;
GUID_t guid;

class SecurityAuthenticationTest : public ::testing::Test
{
    protected:

        virtual void SetUp()
        {
            SecurityPluginFactory::set_auth_plugin(auth_plugin_);
        }

        virtual void TearDown()
        {
            SecurityPluginFactory::release_auth_plugin();
        }

        void initialization_ok()
        {
            DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
            DefaultValue<const GUID_t&>::Set(guid);
            MockIdentityHandle identity_handle;
            MockIdentityHandle* p_identity_handle = &identity_handle;

            EXPECT_CALL(*auth_plugin_, validate_local_identity(_,_,_,_,_,_)).Times(1).
                WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_OK)));
            EXPECT_CALL(participant_, createWriter(_,_,_,_,_,_)).Times(1).
                WillOnce(Return(true));
            EXPECT_CALL(participant_, createReader(_,_,_,_,_,_,_)).Times(1).
                WillOnce(Return(true));

            ASSERT_TRUE(manager_.init());
        }


    public:

        SecurityAuthenticationTest() : auth_plugin_(new MockAuthenticationPlugin()), manager_(&participant_) {}
        MockAuthenticationPlugin* auth_plugin_;
        NiceMock<RTPSParticipantImpl> participant_;
        SecurityManager manager_;
};

TEST_F(SecurityAuthenticationTest, initialization_auth_nullptr)
{
    SecurityPluginFactory::release_auth_plugin();
    DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
    DefaultValue<const GUID_t&>::Set(guid);

    ASSERT_FALSE(manager_.init());
}

TEST_F(SecurityAuthenticationTest, initialization_auth_failed)
{
    DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
    DefaultValue<const GUID_t&>::Set(guid);

    EXPECT_CALL(*auth_plugin_, validate_local_identity(_,_,_,_,_,_)).Times(1).
        WillOnce(Return(ValidationResult_t::VALIDATION_FAILED));

    ASSERT_FALSE(manager_.init());
}

TEST_F(SecurityAuthenticationTest, initialization_fail_participant_stateless_message_writer)
{
    DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
    DefaultValue<const GUID_t&>::Set(guid);
    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_local_identity(_,_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_OK)));
    EXPECT_CALL(participant_, createWriter(_,_,_,_,_,_)).Times(1).
        WillOnce(Return(false));

    ASSERT_FALSE(manager_.init());
}

TEST_F(SecurityAuthenticationTest, initialization_fail_participant_stateless_message_reader)
{
    DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
    DefaultValue<const GUID_t&>::Set(guid);
    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_local_identity(_,_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_OK)));
    EXPECT_CALL(participant_, createWriter(_,_,_,_,_,_)).Times(1).
        WillOnce(Return(true));
    EXPECT_CALL(participant_, createReader(_,_,_,_,_,_,_)).Times(1).
        WillOnce(Return(false));

    ASSERT_FALSE(manager_.init());
}

TEST_F(SecurityAuthenticationTest, initialization_auth_retry)
{
    DefaultValue<const RTPSParticipantAttributes&>::Set(pattr);
    DefaultValue<const GUID_t&>::Set(guid);
    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_local_identity(_,_,_,_,_,_)).Times(2).
        WillOnce(Return(ValidationResult_t::VALIDATION_PENDING_RETRY)).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_OK)));
    EXPECT_CALL(participant_, createWriter(_,_,_,_,_,_)).Times(1).
        WillOnce(Return(true));
    EXPECT_CALL(participant_, createReader(_,_,_,_,_,_,_)).Times(1).
        WillOnce(Return(true));

    ASSERT_TRUE(manager_.init());
}


TEST_F(SecurityAuthenticationTest, initialization_ok)
{
    initialization_ok();
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_fail)
{
    initialization_ok();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(Return(ValidationResult_t::VALIDATION_FAILED));

    GUID_t remote_participant_key;
    ASSERT_FALSE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_ok)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_OK)));

    GUID_t remote_participant_key;
    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_pending_handshake_message)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE)));

    GUID_t remote_participant_key;
    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_pending_handshake_request_fail)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(Return(ValidationResult_t::VALIDATION_FAILED));

    GUID_t remote_participant_key;
    ASSERT_FALSE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_pending_handshake_request_ok)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;
    MockHandshakeHandle handshake_handle;
    MockHandshakeHandle* p_handshake_handle = &handshake_handle;
    HandshakeMessageToken* p_handshake_message = new HandshakeMessageToken();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_handshake_handle), 
                    SetArgPointee<1>(p_handshake_message), Return(ValidationResult_t::VALIDATION_OK)));

    GUID_t remote_participant_key;
    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validation_remote_identity_pending_handshake_request_ok_with_final_message)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;
    MockHandshakeHandle handshake_handle;
    MockHandshakeHandle* p_handshake_handle = &handshake_handle;
    HandshakeMessageToken* p_handshake_message = new HandshakeMessageToken();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_handshake_handle), 
                    SetArgPointee<1>(p_handshake_message), Return(ValidationResult_t::VALIDATION_OK_WITH_FINAL_MESSAGE)));

    GUID_t remote_participant_key;
    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_ok)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;
    MockHandshakeHandle handshake_handle;
    MockHandshakeHandle* p_handshake_handle = &handshake_handle;
    HandshakeMessageToken* p_handshake_message = new HandshakeMessageToken();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_handshake_handle), 
                    SetArgPointee<1>(p_handshake_message), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE)));

    GUID_t remote_participant_key;
    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_validate_remote_fail_and_then_ok)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;
    MockHandshakeHandle handshake_handle;
    MockHandshakeHandle* p_handshake_handle = &handshake_handle;
    HandshakeMessageToken* p_handshake_message = new HandshakeMessageToken();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(Return(ValidationResult_t::VALIDATION_FAILED));

    GUID_t remote_participant_key;
    ASSERT_FALSE(manager_.discovered_participant(IdentityToken(), remote_participant_key));

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_handshake_handle), 
                    SetArgPointee<1>(p_handshake_message), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE)));

    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

TEST_F(SecurityAuthenticationTest, discovered_participant_begin_handshake_request_fail_and_then_ok)
{
    initialization_ok();

    MockIdentityHandle identity_handle;
    MockIdentityHandle* p_identity_handle = &identity_handle;
    MockHandshakeHandle handshake_handle;
    MockHandshakeHandle* p_handshake_handle = &handshake_handle;
    HandshakeMessageToken* p_handshake_message = new HandshakeMessageToken();

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_identity_handle), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_REQUEST)));
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(Return(ValidationResult_t::VALIDATION_FAILED));

    GUID_t remote_participant_key;
    ASSERT_FALSE(manager_.discovered_participant(IdentityToken(), remote_participant_key));

    EXPECT_CALL(*auth_plugin_, validate_remote_identity_rvr(_,_,_,_,_)).Times(0);
    EXPECT_CALL(*auth_plugin_, begin_handshake_request(_,_,_,_,_)).Times(1).
        WillOnce(DoAll(SetArgPointee<0>(p_handshake_handle), 
                    SetArgPointee<1>(p_handshake_message), Return(ValidationResult_t::VALIDATION_PENDING_HANDSHAKE_MESSAGE)));

    ASSERT_TRUE(manager_.discovered_participant(IdentityToken(), remote_participant_key));
}

int main(int argc, char **argv)
{
    testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}