feat(CIE): Implement OIDC RP Service with login, callback, and session management
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#include "common/OidcUserClaims.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace visione::oidc
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string claimString(const Json::Value &value,
|
||||
const char *primary,
|
||||
const char *secondary = nullptr)
|
||||
{
|
||||
const auto primaryValue = value.get(primary, "");
|
||||
if (primaryValue.isString() && !primaryValue.asString().empty())
|
||||
{
|
||||
return primaryValue.asString();
|
||||
}
|
||||
if (secondary)
|
||||
{
|
||||
const auto secondaryValue = value.get(secondary, "");
|
||||
if (secondaryValue.isString())
|
||||
{
|
||||
return secondaryValue.asString();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string trimFiscalPrefix(std::string value)
|
||||
{
|
||||
const std::string prefix = "TINIT-";
|
||||
if (value.rfind(prefix, 0) == 0)
|
||||
{
|
||||
value.erase(0, prefix.size());
|
||||
}
|
||||
std::transform(value.begin(),
|
||||
value.end(),
|
||||
value.begin(),
|
||||
[](unsigned char ch) { return static_cast<char>(std::toupper(ch)); });
|
||||
return value;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::optional<NormalizedUserClaims> normalizeIdTokenClaims(
|
||||
const std::string &issuer,
|
||||
const Json::Value &claims)
|
||||
{
|
||||
if (!claims.isObject())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto subject = claims.get("sub", "").asString();
|
||||
const auto fiscal = trimFiscalPrefix(
|
||||
claims.get("fiscal_number",
|
||||
claims.get("https://attributes.eid.gov.it/fiscal_number", ""))
|
||||
.asString());
|
||||
if (subject.empty() || fiscal.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
NormalizedUserClaims user;
|
||||
user.issuer = issuer;
|
||||
user.subject = subject;
|
||||
user.firstName = claims.get("given_name", "").asString();
|
||||
user.lastName = claims.get("family_name", "").asString();
|
||||
user.email = claims.get("email", "").asString();
|
||||
user.fiscalCode = fiscal;
|
||||
user.rawClaims = claims;
|
||||
return user;
|
||||
}
|
||||
|
||||
std::optional<NormalizedUserClaims> mergeUserClaims(
|
||||
const std::string &issuer,
|
||||
const Json::Value &idTokenClaims,
|
||||
const Json::Value &userinfoClaims)
|
||||
{
|
||||
if (!idTokenClaims.isObject() || !userinfoClaims.isObject())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Json::Value merged = idTokenClaims;
|
||||
for (const auto &name : userinfoClaims.getMemberNames())
|
||||
{
|
||||
merged[name] = userinfoClaims[name];
|
||||
}
|
||||
|
||||
const auto subject = claimString(merged, "sub");
|
||||
const auto fiscal = trimFiscalPrefix(claimString(
|
||||
merged,
|
||||
"fiscal_number",
|
||||
"https://attributes.eid.gov.it/fiscal_number"));
|
||||
if (subject.empty() || fiscal.empty())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
NormalizedUserClaims user;
|
||||
user.issuer = issuer;
|
||||
user.subject = subject;
|
||||
user.firstName = claimString(merged, "given_name");
|
||||
user.lastName = claimString(merged, "family_name");
|
||||
user.email = claimString(merged, "email");
|
||||
user.fiscalCode = fiscal;
|
||||
user.rawClaims = merged;
|
||||
return user;
|
||||
}
|
||||
} // namespace visione::oidc
|
||||
Reference in New Issue
Block a user