Skip to content

Commit ebeed21

Browse files
mowijoKRJ-RTX
authored andcommitted
[cpp][pistache-server] Add support for HTTP Bearer authentication.
1 parent 94ce7ce commit ebeed21

5 files changed

Lines changed: 141 additions & 10 deletions

File tree

modules/openapi-generator/src/main/resources/cpp-pistache-server/api-base-header.mustache

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,18 @@ namespace {{apiNamespace}}
2424
} HttpBasicCredentials;
2525

2626
typedef std::function<bool(HttpBasicCredentials &)> BasicCredentialsAuthenticator;
27-
{{/isBasicBasic}}{{/authMethods}}
27+
{{/isBasicBasic}}
28+
29+
{{#isBasicBearer}}
30+
typedef struct
31+
{
32+
std::string token;
33+
std::unique_ptr<void, std::function<void(void*)>> userdata;
34+
} HttpBearerToken;
35+
36+
typedef std::function<bool(HttpBearerToken &)> BearerTokenAuthenticator;
37+
{{/isBasicBearer}}
38+
{{/authMethods}}
2839

2940

3041

@@ -35,18 +46,23 @@ public:
3546
virtual void init() = 0;
3647

3748
{{#authMethods}}{{#isBasicBasic}}
38-
bool canCredentialsBeAccepted(HttpBasicCredentials& credentials) const;
3949
void setBasicCredentialsAuthenticator( const BasicCredentialsAuthenticator &newBasicCredentialsAuthenticator)
4050
{
4151
basicCredentialsAuthenticator = newBasicCredentialsAuthenticator;
4252
}
43-
44-
{{/isBasicBasic}}{{/authMethods}}
53+
{{/isBasicBasic}}
54+
{{#isBasicBearer}}
55+
void setBearerTokenAuthenticator( const BearerTokenAuthenticator &newbearerTokenAuthenticator)
56+
{
57+
bearerTokenAuthenticator = newbearerTokenAuthenticator;
58+
}
59+
{{/isBasicBearer}}{{/authMethods}}
4560

4661

4762
protected:
4863
const std::shared_ptr<Pistache::Rest::Router> router;
4964
{{#authMethods}}{{#isBasicBasic}}std::optional<BasicCredentialsAuthenticator> basicCredentialsAuthenticator;{{/isBasicBasic}}{{/authMethods}}
65+
{{#authMethods}}{{#isBasicBearer}}std::optional<BearerTokenAuthenticator> bearerTokenAuthenticator;{{/isBasicBearer}}{{/authMethods}}
5066

5167

5268
};

modules/openapi-generator/src/main/resources/cpp-pistache-server/api-header.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private:
7979
{{#allParams}}
8080
/// <param name="{{paramName}}">{{description}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}</param>
8181
{{/allParams}}
82-
virtual void {{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials, {{/isBasicBasic}}{{/authMethods}} {{#allParams}}const {{#isModel}}{{^isOptional}}{{modelNamespace}}::{{/isOptional}}{{/isModel}}{{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) = 0;
82+
virtual void {{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials, {{/isBasicBasic}}{{#isBasicBearer}}const HttpBearerToken &accessToken, {{/isBasicBearer}}{{/authMethods}} {{#allParams}}const {{#isModel}}{{^isOptional}}{{modelNamespace}}::{{/isOptional}}{{/isModel}}{{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) = 0;
8383
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
8484
{{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
8585
virtual void {{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;

modules/openapi-generator/src/main/resources/cpp-pistache-server/api-impl-header.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public:
3535

3636
{{#operation}}
3737
{{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
38-
void {{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials,{{/isBasicBasic}}{{/authMethods}}{{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response);
38+
void {{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials,{{/isBasicBasic}}{{#isBasicBearer}}const HttpBearerToken &bearerToken, {{/isBasicBearer}}{{/authMethods}}{{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response);
3939
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
4040
{{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
4141
void {{operationIdSnakeCase}}(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response);

modules/openapi-generator/src/main/resources/cpp-pistache-server/api-impl-source.mustache

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,71 @@ using namespace {{modelNamespace}};{{/hasModelImport}}
7171
or a mix.
7272

7373
Until you do either, protected resources will result in a 401.
74-
*/{{/isBasicBasic}}{{/authMethods}}
74+
*/{{/isBasicBasic}}
75+
{{#isBasicBearer}}/*
76+
77+
Http Basic Bearer
78+
===============
79+
80+
Do this in the individual classes in the constructor
81+
82+
this->setBearerTokenAuthenticator(
83+
[](HttpBearerToken &token)->bool
84+
{
85+
if(token.token == "Zm9vYmFyCg==")
86+
{
87+
const int userIdOfFoo = 99;
88+
token.userdata = std::unique_ptr<void,std::function<void(void*)>>(
89+
reinterpret_cast<void*>(new int(userIdOfFoo)),
90+
[&](void* ptr)
91+
{
92+
int * value = reinterpret_cast<int*>(ptr);
93+
delete value;
94+
}
95+
);
96+
return true;
97+
}
98+
return false;
99+
}
100+
);
101+
102+
or in main:
103+
104+
for (auto api : apiImpls) {
105+
api->init();
106+
107+
api->setBearerTokenAuthenticator(
108+
[](HttpBearerToken &token)->bool
109+
{
110+
if(token.token == "Zm9vYmFyCg==")
111+
{
112+
const int userIdOfFoo = 99;
113+
token.userdata = std::unique_ptr<void,std::function<void(void*)>>(
114+
reinterpret_cast<void*>(new int(userIdOfFoo)),
115+
[&](void* ptr)
116+
{
117+
int * value = reinterpret_cast<int*>(ptr);
118+
delete value;
119+
}
120+
);
121+
return true;
122+
}
123+
return false;
124+
}
125+
);
126+
}
127+
128+
or a mix.
129+
130+
Until you do either, protected resources will result in a 401.
131+
*/{{/isBasicBearer}}
132+
{{/authMethods}}
75133

76134
}
77135

78136
{{#operation}}
79137
{{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
80-
void {{classname}}Impl::{{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials, {{/isBasicBasic}}{{/authMethods}}{{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) {
138+
void {{classname}}Impl::{{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}const HttpBasicCredentials &credentials, {{/isBasicBasic}}{{#isBasicBearer}}const HttpBearerToken &bearerToken, {{/isBasicBearer}}{{/authMethods}}{{#allParams}}const {{{dataType}}} &{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}Pistache::Http::ResponseWriter &response) {
81139
response.send(Pistache::Http::Code::Ok, "Do some magic\n");
82140
}
83141
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}

modules/openapi-generator/src/main/resources/cpp-pistache-server/api-source.mustache

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,22 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
121121
122122
{{/bodyParam}}
123123
{{/hasBodyParam}}
124+
125+
{{#authMethods}}
126+
#ifndef HTTP_BASIC_AUTH_DEFINED
127+
#define HTTP_BASIC_AUTH_DEFINED 0
128+
#endif
129+
#ifndef HTTP_BEARER_AUTH_DEFINED
130+
#define HTTP_BEARER_AUTH_DEFINED 0
131+
#endif
132+
{{/authMethods}}
133+
134+
135+
124136
{{#authMethods}}{{#isBasicBasic}}
137+
#undef HTTP_BASIC_AUTH_DEFINED
138+
#define HTTP_BASIC_AUTH_DEFINED 1
139+
125140
auto basicAuthHeader = request.headers().tryGet<Pistache::Http::Header::Authorization>();
126141

127142
if( (!basicAuthHeader) || (basicAuthHeader->getMethod() != Pistache::Http::Header::Authorization::Method::Basic))
@@ -145,10 +160,36 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
145160
{{/isBasicBasic}}{{/authMethods}}
146161

147162
{{#authMethods}}{{#isBasicBearer}}
148-
/* BASIC BEARER */
163+
#undef HTTP_BEARER_AUTH_DEFINED
164+
#define HTTP_BEARER_AUTH_DEFINED 1
165+
auto bearerAuthHeader = request.headers().tryGet<Pistache::Http::Header::Authorization>();
166+
167+
if( (!bearerAuthHeader) || (bearerAuthHeader->getMethod() != Pistache::Http::Header::Authorization::Method::Bearer))
168+
{
169+
response.send(Pistache::Http::Code::Unauthorized, "");
170+
return;
171+
}
172+
std::string completeHeaderValue = bearerAuthHeader->value();
173+
const std::string tokenAsString(completeHeaderValue.begin() + std::string("Bearer ").length(), completeHeaderValue.end());
174+
175+
HttpBearerToken bearerToken{tokenAsString};
176+
if( ! this->bearerTokenAuthenticator.has_value())
177+
{
178+
response.send(Pistache::Http::Code::Unauthorized, "");
179+
return;
180+
}
181+
182+
if( ! this->bearerTokenAuthenticator.value()(bearerToken))
183+
{
184+
response.send(Pistache::Http::Code::Unauthorized, "");
185+
return;
186+
}
187+
188+
189+
149190
{{/isBasicBearer}}{{/authMethods}}
150191

151-
this->{{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}credentials,{{/isBasicBasic}}{{/authMethods}}{{#allParams}}{{paramName}}, {{/allParams}}response);
192+
this->{{operationIdSnakeCase}}({{#authMethods}}{{#isBasicBasic}}credentials,{{/isBasicBasic}}{{#isBasicBearer}}bearerToken,{{/isBasicBearer}}{{/authMethods}}{{#allParams}}{{paramName}}, {{/allParams}}response);
152193
{{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
153194
{{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
154195
try {
@@ -166,6 +207,22 @@ void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Reque
166207
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
167208
}
168209

210+
#define REST_PATH "{{{vendorExtensions.x-codegen-pistache-path}}}" {{! this is nessecary, because the path does not exist in the authMethods scope.}}
211+
{{#authMethods}}
212+
{{! This static assert may be rendered more that once, so the compilation will fail even harder!}}
213+
static_assert(HTTP_BASIC_AUTH_DEFINED + HTTP_BEARER_AUTH_DEFINED < 2, "Path '" REST_PATH "' has more than one security scheme specified, and the Pistache server generator does not support that." );
214+
{{/authMethods}}
215+
#undef REST_PATH
216+
217+
{{#authMethods}}
218+
#ifdef HTTP_BEARER_AUTH_DEFINED
219+
#undef HTTP_BEARER_AUTH_DEFINED
220+
#endif
221+
#ifdef HTTP_BASIC_AUTH_DEFINED
222+
#undef HTTP_BASIC_AUTH_DEFINED
223+
#endif
224+
{{/authMethods}}
225+
169226
}
170227
{{/operation}}
171228

0 commit comments

Comments
 (0)