CCF
Loading...
Searching...
No Matches
helpers.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
8
10{
11 inline AuthnPolicies member_sig_only_policies(const std::string& gov_msg_type)
12 {
13 return {std::make_shared<MemberCOSESign1AuthnPolicy>(gov_msg_type)};
14 }
15
17 const std::string& gov_msg_type)
18 {
19 return {std::make_shared<ActiveMemberCOSESign1AuthnPolicy>(gov_msg_type)};
20 }
21
22 // Wrapper for reporting errors, which both logs them under the [gov] tag
23 // and sets the HTTP response
24 static void set_gov_error(
25 const std::shared_ptr<ccf::RpcContext>& rpc_ctx,
26 ccf::http_status status,
27 const std::string& code,
28 std::string&& msg)
29 {
31 "{} {} returning error {}: {}",
32 rpc_ctx->get_request_verb().c_str(),
33 rpc_ctx->get_request_path(),
34 status,
35 msg);
36
37 rpc_ctx->set_error(status, code, std::move(msg));
38 }
39
40 template <typename EntityType>
41 std::optional<EntityType> parse_hex_id(const std::string& s)
42 {
43 // Entity IDs must be hex encoding of 32 bytes
44
45 // Must be 64 characters in length
46 if (s.size() != 64)
47 {
48 return std::nullopt;
49 }
50
51 // Must contain only hex characters
52 if (std::any_of(s.begin(), s.end(), [](char c) {
53 return (c < '0') || (c > '9' && c < 'A') || (c > 'F' && c < 'a') ||
54 (c > 'f');
55 }))
56 {
57 return std::nullopt;
58 }
59
60 return EntityType(s);
61 }
62
63 // Extract memberId from path parameter, confirm it is a plausible ID
65 const std::shared_ptr<ccf::RpcContext>& rpc_ctx, ccf::MemberId& member_id)
66 {
67 // Extract member ID from path parameter
68 std::string member_id_str;
69 std::string error;
71 rpc_ctx->get_request_path_params(), "memberId", member_id_str, error))
72 {
73 detail::set_gov_error(
74 rpc_ctx,
75 HTTP_STATUS_BAD_REQUEST,
76 ccf::errors::InvalidResourceName,
77 std::move(error));
78 return false;
79 }
80
81 // Parse member ID from string
82 const auto member_id_opt = parse_hex_id<ccf::MemberId>(member_id_str);
83 if (!member_id_opt.has_value())
84 {
85 detail::set_gov_error(
86 rpc_ctx,
87 HTTP_STATUS_BAD_REQUEST,
88 ccf::errors::InvalidResourceName,
89 fmt::format(
90 "'{}' is not a valid hex-encoded member ID", member_id_str));
91 return false;
92 }
93
94 member_id = member_id_opt.value();
95 return true;
96 }
97
98 // Like try_parse_member_id, but also confirm that the parsed member ID
99 // matches the COSE signer
101 const ccf::MemberCOSESign1AuthnIdentity& cose_ident,
102 const std::shared_ptr<ccf::RpcContext>& rpc_ctx,
103 ccf::MemberId& member_id)
104 {
105 if (!try_parse_member_id(rpc_ctx, member_id))
106 {
107 return false;
108 }
109
110 if (member_id != cose_ident.member_id)
111 {
112 detail::set_gov_error(
113 rpc_ctx,
114 HTTP_STATUS_BAD_REQUEST,
115 ccf::errors::InvalidResourceName,
116 "Authenticated member id does not match URL");
117 return false;
118 }
119
120 return true;
121 }
122
123 // Extract userId from path parameter, confirm it is a plausible ID
124 inline bool try_parse_user_id(
125 const std::shared_ptr<ccf::RpcContext>& rpc_ctx, ccf::UserId& user_id)
126 {
127 // Extract user ID from path parameter
128 std::string user_id_str;
129 std::string error;
131 rpc_ctx->get_request_path_params(), "userId", user_id_str, error))
132 {
133 detail::set_gov_error(
134 rpc_ctx,
135 HTTP_STATUS_BAD_REQUEST,
136 ccf::errors::InvalidResourceName,
137 std::move(error));
138 return false;
139 }
140
141 // Parse user ID from string
142 const auto user_id_opt = parse_hex_id<ccf::UserId>(user_id_str);
143 if (!user_id_opt.has_value())
144 {
145 detail::set_gov_error(
146 rpc_ctx,
147 HTTP_STATUS_BAD_REQUEST,
148 ccf::errors::InvalidResourceName,
149 fmt::format("'{}' is not a valid hex-encoded user ID", user_id_str));
150 return false;
151 }
152
153 user_id = user_id_opt.value();
154 return true;
155 }
156
157 // Extract proposalId from path parameter, confirm it is a plausible ID
159 const std::shared_ptr<ccf::RpcContext>& rpc_ctx,
160 ccf::ProposalId& proposal_id)
161 {
162 // Extract proposal ID from path parameter
163 std::string proposal_id_str;
164 std::string error;
166 rpc_ctx->get_request_path_params(),
167 "proposalId",
168 proposal_id_str,
169 error))
170 {
171 detail::set_gov_error(
172 rpc_ctx,
173 HTTP_STATUS_BAD_REQUEST,
174 ccf::errors::InvalidResourceName,
175 std::move(error));
176 return false;
177 }
178
179 // Parse proposal ID from string
180 const auto proposal_id_opt = parse_hex_id<ccf::ProposalId>(proposal_id_str);
181 if (!proposal_id_opt.has_value())
182 {
183 detail::set_gov_error(
184 rpc_ctx,
185 HTTP_STATUS_BAD_REQUEST,
186 ccf::errors::InvalidResourceName,
187 fmt::format(
188 "'{}' is not a valid hex-encoded proposal ID", proposal_id_str));
189 return false;
190 }
191
192 proposal_id = proposal_id_opt.value();
193 return true;
194 }
195
196 // Like try_parse_proposal_id, but also confirm that the parsed proposal ID
197 // matches a signed COSE header
199 const ccf::MemberCOSESign1AuthnIdentity& cose_ident,
200 const std::shared_ptr<ccf::RpcContext>& rpc_ctx,
201 ccf::ProposalId& proposal_id)
202 {
203 if (!try_parse_proposal_id(rpc_ctx, proposal_id))
204 {
205 return false;
206 }
207
208 const auto& signed_proposal_id =
210 if (
211 !signed_proposal_id.has_value() ||
212 signed_proposal_id.value() != proposal_id)
213 {
214 detail::set_gov_error(
215 rpc_ctx,
216 HTTP_STATUS_BAD_REQUEST,
217 ccf::errors::InvalidResourceName,
218 "Authenticated proposal id does not match URL");
219 return false;
220 }
221
222 return true;
223 }
224
225 // Extract nodeId from path parameter, confirm it is a plausible ID
226 inline bool try_parse_node_id(
227 const std::shared_ptr<ccf::RpcContext>& rpc_ctx, ccf::NodeId& node_id)
228 {
229 // Extract node ID from path parameter
230 std::string node_id_str;
231 std::string error;
233 rpc_ctx->get_request_path_params(), "nodeId", node_id_str, error))
234 {
235 detail::set_gov_error(
236 rpc_ctx,
237 HTTP_STATUS_BAD_REQUEST,
238 ccf::errors::InvalidResourceName,
239 std::move(error));
240 return false;
241 }
242
243 // Parse node ID from string
244 const auto node_id_opt = parse_hex_id<ccf::NodeId>(node_id_str);
245 if (!node_id_opt.has_value())
246 {
247 detail::set_gov_error(
248 rpc_ctx,
249 HTTP_STATUS_BAD_REQUEST,
250 ccf::errors::InvalidResourceName,
251 fmt::format("'{}' is not a valid hex-encoded node ID", node_id_str));
252 return false;
253 }
254
255 node_id = node_id_opt.value();
256 return true;
257 }
258}
#define GOV_INFO_FMT
Definition gov_logging.h:10
bool get_path_param(const ccf::PathParams &params, const std::string &param_name, T &value, std::string &error)
Definition endpoint_registry.h:64
Definition helpers.h:10
bool try_parse_user_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::UserId &user_id)
Definition helpers.h:124
bool try_parse_member_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::MemberId &member_id)
Definition helpers.h:64
bool try_parse_proposal_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::ProposalId &proposal_id)
Definition helpers.h:158
bool try_parse_signed_member_id(const ccf::MemberCOSESign1AuthnIdentity &cose_ident, const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::MemberId &member_id)
Definition helpers.h:100
bool try_parse_signed_proposal_id(const ccf::MemberCOSESign1AuthnIdentity &cose_ident, const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::ProposalId &proposal_id)
Definition helpers.h:198
std::optional< EntityType > parse_hex_id(const std::string &s)
Definition helpers.h:41
AuthnPolicies member_sig_only_policies(const std::string &gov_msg_type)
Definition helpers.h:11
bool try_parse_node_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::NodeId &node_id)
Definition helpers.h:226
AuthnPolicies active_member_sig_only_policies(const std::string &gov_msg_type)
Definition helpers.h:16
std::vector< std::shared_ptr< AuthnPolicy > > AuthnPolicies
Definition authentication_types.h:47
llhttp_status http_status
Definition http_status.h:9
std::string ProposalId
Definition proposals.h:40
@ error
Definition tls_session.h:23
Value & value()
Definition entity_id.h:67
std::optional< std::string > gov_msg_proposal_id
Definition cose_auth.h:21
Definition cose_auth.h:59
GovernanceProtectedHeader protected_header
Definition cose_auth.h:67
MemberId member_id
Definition cose_auth.h:61