@@ -27,12 +27,13 @@ struct OAuthOutput {
2727 std::string secret;
2828 std::string accessToken;
2929 std::string refreshToken;
30+ std::string roles;
3031};
3132} // namespace opencmw
3233
3334ENABLE_REFLECTION_FOR (opencmw::OAuthContext, secretToken)
3435ENABLE_REFLECTION_FOR (opencmw::OAuthInput, scope, clientId, clientSecret, secret, publicKey)
35- ENABLE_REFLECTION_FOR (opencmw::OAuthOutput, authorizationUri, secret, accessToken, refreshToken)
36+ ENABLE_REFLECTION_FOR (opencmw::OAuthOutput, authorizationUri, secret, accessToken, refreshToken, roles )
3637
3738namespace opencmw {
3839
@@ -91,13 +92,14 @@ class OAuthClient {
9192 StrictUri _redirectUri;
9293 StrictUri _endpoint;
9394 StrictUri _tokenEndpoint;
95+ StrictUri _userinfoEndpoint;
9496 httplib::Server _srv;
9597 std::unique_ptr<std::thread> _thread;
9698 std::function<void (const std::string &code, const std::string &state)> _endpointCallback;
9799
98100public:
99- explicit OAuthClient (StrictUri redirectUri, StrictUri endpoint, StrictUri tokenEndpoint)
100- : _redirectUri(redirectUri), _endpoint(endpoint), _tokenEndpoint(tokenEndpoint) {
101+ explicit OAuthClient (StrictUri redirectUri, StrictUri endpoint, StrictUri tokenEndpoint, StrictUri userinfoEndpoint = StrictUri( " " ) )
102+ : _redirectUri(redirectUri), _endpoint(endpoint), _tokenEndpoint(tokenEndpoint), _userinfoEndpoint(userinfoEndpoint) {
101103 _srv.Get (" /" , [&](const httplib::Request req, httplib::Response &res) {
102104 std::string code, state, error;
103105 // response as per https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2
@@ -213,6 +215,33 @@ class OAuthClient {
213215 return getAccessToken ({ { " grant_type" , " refresh_token" }, { " refresh_token" , refreshToken }, { " client_id" , clientId } });
214216 }
215217
218+ std::string getAssignedRoles (const std::string &accessToken) {
219+ auto client = getClient (_userinfoEndpoint);
220+ if (!client) {
221+ return {};
222+ }
223+
224+ httplib::Headers headers{ { { " Authorization" , " Bearer " + accessToken } } };
225+ auto res = client->Get (*_userinfoEndpoint.path (), headers);
226+ if (!res || res->status != 200 ) {
227+ return {};
228+ }
229+ std::string s{ res->body .c_str () };
230+ const std::string marker{ " \" account\" :{\" roles\" :[" };
231+ auto start = s.find (marker);
232+ if (start == std::string::npos) {
233+ return {};
234+ }
235+ start += marker.size ();
236+ const auto end = s.find (" ]" , start);
237+ if (end == std::string::npos) {
238+ return {};
239+ }
240+ std::string roles = s.substr (start, end - start);
241+ std::erase (roles, ' \" ' );
242+ return roles;
243+ }
244+
216245 void stop () {
217246 _srv.stop ();
218247 _thread->join ();
@@ -246,11 +275,11 @@ using OAuthWorkerType = majordomo::Worker<"/oauth", OAuthContext, OAuthInput, OA
246275
247276class OAuthWorker : public OAuthWorkerType {
248277public:
249- explicit OAuthWorker (StrictUri redirectUri, StrictUri endpoint, StrictUri tokenEndpoint, StrictUri brokerAddress, const zmq::Context &context, majordomo::Settings settings = {})
250- : OAuthWorkerType(brokerAddress, {}, context, settings), _client(redirectUri, endpoint, tokenEndpoint), _keystore(brokerAddress, context, settings) { init (); };
278+ explicit OAuthWorker (StrictUri redirectUri, StrictUri endpoint, StrictUri tokenEndpoint, StrictUri userinfoEndpoint, StrictUri brokerAddress, const zmq::Context &context, majordomo::Settings settings = {})
279+ : OAuthWorkerType(brokerAddress, {}, context, settings), _client(redirectUri, endpoint, tokenEndpoint, userinfoEndpoint ), _keystore(brokerAddress, context, settings) { init (); };
251280 template <typename BrokerType>
252- explicit OAuthWorker (StrictUri redirecturi, StrictUri endpoint, StrictUri tokenEndpoint, const BrokerType &broker)
253- : OAuthWorkerType(broker, {}), _client(redirecturi, endpoint, tokenEndpoint), _keystore(broker) { init (); };
281+ explicit OAuthWorker (StrictUri redirecturi, StrictUri endpoint, StrictUri tokenEndpoint, StrictUri userinfoEndpoint, const BrokerType &broker)
282+ : OAuthWorkerType(broker, {}), _client(redirecturi, endpoint, tokenEndpoint, userinfoEndpoint ), _keystore(broker) { init (); };
254283 ~OAuthWorker () {
255284 _keystore.shutdown ();
256285 _keystoreThread.join ();
@@ -292,6 +321,9 @@ class OAuthWorker : public OAuthWorkerType {
292321 const auto access = _client.requestToken (code, in.clientId );
293322 out.accessToken = access.accessToken ._token ;
294323 out.refreshToken = access.refreshToken ._token ;
324+
325+ // get RBAC roles
326+ out.roles = _client.getAssignedRoles (out.accessToken );
295327 }
296328 });
297329 _keystoreThread = std::thread ([this ] { _keystore.run (); });
0 commit comments