Skip to content

Commit

Permalink
[ROS2] port package to ament_cmake / ROS 2 API (#18)
Browse files Browse the repository at this point in the history
* update package manifest

* use package name for builtin types in service

* remove Travis for now

* update code to use ROS 2 API

* rewrite test into Python based launch

* update CMake code
  • Loading branch information
dirk-thomas authored Sep 19, 2019
1 parent 899a116 commit 8457bf4
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 156 deletions.
16 changes: 0 additions & 16 deletions .travis.yml

This file was deleted.

100 changes: 48 additions & 52 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,75 +1,71 @@
cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)
project(rosauth)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp message_generation)
find_package(ament_cmake_ros REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(OpenSSL REQUIRED)

#######################################
## Declare ROS messages and services ##
#######################################

## Generate services in the 'srv' folder
add_service_files(
FILES
Authentication.srv
)

## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
)

###################################################
## Declare things to be passed to other projects ##
###################################################

## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(CATKIN_DEPENDS roscpp message_runtime)

###########
## Build ##
###########
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()

include_directories(
${catkin_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIR}
rosidl_generate_interfaces(${PROJECT_NAME}
srv/Authentication.srv
DEPENDENCIES builtin_interfaces
)

## Declare a cpp executable
add_executable(ros_mac_authentication src/ros_mac_authentication.cpp)
add_dependencies(ros_mac_authentication ${PROJECT_NAME})
ament_target_dependencies(ros_mac_authentication rclcpp)
rosidl_target_interfaces(
ros_mac_authentication ${PROJECT_NAME} "rosidl_typesupport_cpp")
target_link_libraries(ros_mac_authentication crypto)

## Specify libraries to link a library or executable target against
target_link_libraries(ros_mac_authentication ${catkin_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)

add_dependencies(ros_mac_authentication ${PROJECT_NAME}_gencpp)
ament_export_dependencies(rosidl_default_runtime)

#############
## Install ##
#############
ament_package()

## Mark executables and/or libraries for installation
install(TARGETS ros_mac_authentication
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
RUNTIME DESTINATION lib/${PROJECT_NAME}
)

#############
## Testing ##
#############

if(CATKIN_ENABLE_TESTING)
find_package(rostest REQUIRED)
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
## Add gtest based cpp test target and link libraries
add_executable(ros_mac_authentication_test test/ros_mac_authentication_test.cpp)
add_dependencies(ros_mac_authentication_test ${PROJECT_NAME}_gencpp)
if(MSVC)
target_link_libraries(ros_mac_authentication_test ${catkin_LIBRARIES} ${GTEST_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
else()
target_link_libraries(ros_mac_authentication_test ${catkin_LIBRARIES} ${GTEST_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto dl pthread)
endif()
add_rostest(test/ros_mac_authentication.test)
ament_add_gtest_executable(ros_mac_authentication_test test/ros_mac_authentication_test.cpp)
rosidl_target_interfaces(ros_mac_authentication_test
${PROJECT_NAME} "rosidl_typesupport_cpp")
ament_target_dependencies(ros_mac_authentication_test builtin_interfaces rclcpp)
target_link_libraries(ros_mac_authentication_test crypto dl pthread)

# TODO replace parameter file with just passing the parameter once that is supported
set(PARAMETERS_YAML_FILE "${CMAKE_CURRENT_BINARY_DIR}/secret.yaml")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/test/secret.yaml.in"
"${PARAMETERS_YAML_FILE}"
@ONLY)

set(ROS_MAC_AUTHENTICATION_EXECUTABLE $<TARGET_FILE:ros_mac_authentication>)
set(ROS_MAC_AUTHENTICATION_TEST_EXECUTABLE $<TARGET_FILE:ros_mac_authentication_test>)
set(generated_test_file "${CMAKE_CURRENT_BINARY_DIR}/ros_mac_authentication_test")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/test/ros_mac_authentication_test.py.in"
"${generated_test_file}.py.genexp"
@ONLY)
file(GENERATE
OUTPUT "${generated_test_file}_$<CONFIG>.py"
INPUT "${generated_test_file}.py.genexp"
)
ament_add_test(tests
COMMAND "${generated_test_file}_$<CONFIG>.py"
GENERATE_RESULT_FOR_RETURN_CODE_ZERO)
endif()
18 changes: 11 additions & 7 deletions package.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<package format="2">
<package format="3">
<name>rosauth</name>
<version>1.0.1</version>
<description>Server Side tools for Authorization and Authentication of ROS Clients</description>
Expand All @@ -13,13 +13,17 @@
<url type="bugtracker">https://github.com/GT-RAIL/rosauth/issues</url>
<url type="repository">https://github.com/GT-RAIL/rosauth</url>

<buildtool_depend>catkin</buildtool_depend>
<buildtool_depend>ament_cmake_ros</buildtool_depend>
<build_depend>libssl-dev</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>rclcpp</build_depend>
<buildtool_depend>rosidl_default_generators</buildtool_depend>

<exec_depend>message_runtime</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rclcpp</exec_depend>
<exec_depend>rosidl_default_runtime</exec_depend>

<test_depend>rostest</test_depend>
<member_of_group>rosidl_interface_packages</member_of_group>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
125 changes: 74 additions & 51 deletions src/ros_mac_authentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@

#include <fstream>
#include <openssl/sha.h>
#include <ros/ros.h>
#include <rosauth/Authentication.h>
#include <rclcpp/rclcpp.hpp>
#include <rosauth/srv/authentication.hpp>
#include <sstream>
#include <string>

using namespace std;
using namespace ros;

/*!
* \def SECRET_FILE_PARAM
Expand Down Expand Up @@ -64,44 +63,58 @@ string secret;
// the allowed time delta
double allowed_time_delta;

bool authenticate(rosauth::Authentication::Request &req, rosauth::Authentication::Response &res)
class ServerNode : public rclcpp::Node
{
// keep track of the current time
Time t = Time::now();
// clocks can be out of sync, check which comes later
Duration *diff;
if (req.t > t)
diff = new Duration(req.t - t);
else
diff = new Duration(t - req.t);
bool time_check = allowed_time_delta < 0 || (diff->sec < allowed_time_delta && req.end > t);
delete diff;
public:
explicit ServerNode(
const string & node_name,
const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
: Node(node_name, options)
{}

bool authenticate(
rosauth::srv::Authentication::Request::SharedPtr req,
rosauth::srv::Authentication::Response::SharedPtr res
) {
// keep track of the current time
auto t = this->now();
auto req_t = rclcpp::Time(req->t);
// clocks can be out of sync, check which comes later
rclcpp::Duration diff(0, 0);
if (req_t > t)
diff = req_t - t;
else
diff = t - req_t;
bool time_check = allowed_time_delta < 0 || (diff.seconds() < allowed_time_delta && rclcpp::Time(req->end) > t);

// check if we pass the time requirement
if (time_check)
{
// create the string to hash
stringstream ss;
ss << secret << req.client << req.dest << req.rand << req.t.sec << req.level << req.end.sec;
string local_hash = ss.str();

// check the request
unsigned char sha512_hash[SHA512_DIGEST_LENGTH];
SHA512((unsigned char *)local_hash.c_str(), local_hash.length(), sha512_hash);

// convert to a hex string to compare
char hex[SHA512_DIGEST_LENGTH * 2 + 1];
for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
sprintf(&hex[i * 2], "%02x", sha512_hash[i]);

// an authenticated user must match the MAC string
res.authenticated = (strcmp(hex, req.mac.c_str()) == 0);
}
else
res.authenticated = false;
// check if we pass the time requirement
RCLCPP_INFO(get_logger(), "time_check");
if (time_check)
{
RCLCPP_INFO(get_logger(), "time_check PASSED");
// create the string to hash
stringstream ss;
ss << secret << req->client << req->dest << req->rand << req->t.sec << req->level << req->end.sec;
string local_hash = ss.str();

// check the request
unsigned char sha512_hash[SHA512_DIGEST_LENGTH];
SHA512((unsigned char *)local_hash.c_str(), local_hash.length(), sha512_hash);

// convert to a hex string to compare
char hex[SHA512_DIGEST_LENGTH * 2 + 1];
for (int i = 0; i < SHA512_DIGEST_LENGTH; i++)
sprintf(&hex[i * 2], "%02x", sha512_hash[i]);

// an authenticated user must match the MAC string
res->authenticated = (strcmp(hex, req->mac.c_str()) == 0);
}
else
res->authenticated = false;

return true;
}
return true;
}
};

/*!
* Creates and runs the ros_mac_authentication node.
Expand All @@ -113,24 +126,33 @@ bool authenticate(rosauth::Authentication::Request &req, rosauth::Authentication
int main(int argc, char **argv)
{
// initialize ROS and the node
init(argc, argv, "ros_mac_authentication");
NodeHandle node;
NodeHandle node_param("~");
rclcpp::init(argc, argv);
rclcpp::NodeOptions options;
options.automatically_declare_parameters_from_overrides(true);
auto node = std::make_shared<ServerNode>("ros_mac_authentication", options);

allowed_time_delta = node_param.param(ALLOWED_TIME_DELTA_PARAM, 5);
rclcpp::Parameter param;
if (node->get_parameter(ALLOWED_TIME_DELTA_PARAM, param))
{
allowed_time_delta = param.as_int();
}
else
{
allowed_time_delta = 5;
}

// check if we have to check the secret file
string file;
if (!node_param.getParam(SECRET_FILE_PARAM, file))
rclcpp::Parameter file;
if (!node->get_parameter(SECRET_FILE_PARAM, file))
{
ROS_ERROR("Parameter '%s' not found.", SECRET_FILE_PARAM);
RCLCPP_ERROR(node->get_logger(), "Parameter '%s' not found.", SECRET_FILE_PARAM);
return MISSING_PARAMETER;
}
else
{
// try and load the file
ifstream f;
f.open(file.c_str(), ifstream::in);
f.open(file.as_string().c_str(), ifstream::in);
if (f.is_open())
{
// should be a 1 line file with the string
Expand All @@ -139,21 +161,22 @@ int main(int argc, char **argv)
// check the length of the secret
if (secret.length() != SECRET_LENGTH)
{
ROS_ERROR("Secret string not of length %d.", SECRET_LENGTH);
RCLCPP_ERROR(node->get_logger(), "Secret string not of length %d.", SECRET_LENGTH);
return INVALID_SECRET;
}
else
{
ServiceServer service = node.advertiseService("authenticate", authenticate);
ROS_INFO("ROS Authentication Server Started");
spin();
auto service = node->create_service<rosauth::srv::Authentication>(
"authenticate", std::bind(&ServerNode::authenticate, node, placeholders::_1, placeholders::_2));
RCLCPP_INFO(node->get_logger(), "ROS Authentication Server Started");
rclcpp::spin(node);

return EXIT_SUCCESS;
}
}
else
{
ROS_ERROR("Could not read from file '%s'", file.c_str());
RCLCPP_ERROR(node->get_logger(), "Could not read from file '%s'", file.as_string().c_str());
return FILE_IO_ERROR;
}
}
Expand Down
4 changes: 2 additions & 2 deletions srv/Authentication.srv
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ string dest
# Random string given by the client
string rand
# Time of the authorization request given by the client
time t
builtin_interfaces/Time t
# User level as a string given by the client
string level
# End time of the client's session given by the client
time end
builtin_interfaces/Time end
---
# If the user has proper authentication
bool authenticated
6 changes: 0 additions & 6 deletions test/ros_mac_authentication.test

This file was deleted.

Loading

0 comments on commit 8457bf4

Please sign in to comment.