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