1*0e373b53SMarco Kawajiri #pragma once 2*0e373b53SMarco Kawajiri 3*0e373b53SMarco Kawajiri #include "logging.hpp" 4*0e373b53SMarco Kawajiri 5*0e373b53SMarco Kawajiri #include <format> 6*0e373b53SMarco Kawajiri #include <optional> 7*0e373b53SMarco Kawajiri #include <string> 8*0e373b53SMarco Kawajiri #include <string_view> 9*0e373b53SMarco Kawajiri 10*0e373b53SMarco Kawajiri inline std::optional<std::string_view> mtlsMetaParseSslUser(std::string_view sslUser)11*0e373b53SMarco Kawajiri mtlsMetaParseSslUser(std::string_view sslUser) 12*0e373b53SMarco Kawajiri { 13*0e373b53SMarco Kawajiri // Parses a Meta internal TLS client certificate Subject CN in 14*0e373b53SMarco Kawajiri // '<entityType>:<entity>[/<hostname>]' format and returns the resulting 15*0e373b53SMarco Kawajiri // POSIX-compatible local user name on success, null otherwise. 16*0e373b53SMarco Kawajiri // 17*0e373b53SMarco Kawajiri // Only entityType = "user" is supported for now. 18*0e373b53SMarco Kawajiri // 19*0e373b53SMarco Kawajiri // Example client subject CN -> local user name: 20*0e373b53SMarco Kawajiri // "user:a_username/hostname" -> "a_username" 21*0e373b53SMarco Kawajiri 22*0e373b53SMarco Kawajiri // Parse entityType 23*0e373b53SMarco Kawajiri size_t colonIndex = sslUser.find(':'); 24*0e373b53SMarco Kawajiri if (colonIndex == std::string_view::npos) 25*0e373b53SMarco Kawajiri { 26*0e373b53SMarco Kawajiri BMCWEB_LOG_WARNING("Invalid Meta TLS client cert Subject CN: '{}'", 27*0e373b53SMarco Kawajiri sslUser); 28*0e373b53SMarco Kawajiri return std::nullopt; 29*0e373b53SMarco Kawajiri } 30*0e373b53SMarco Kawajiri 31*0e373b53SMarco Kawajiri std::string_view entityType = sslUser.substr(0, colonIndex); 32*0e373b53SMarco Kawajiri sslUser.remove_prefix(colonIndex + 1); 33*0e373b53SMarco Kawajiri if (entityType != "user") 34*0e373b53SMarco Kawajiri { 35*0e373b53SMarco Kawajiri BMCWEB_LOG_WARNING( 36*0e373b53SMarco Kawajiri "Invalid/unsupported entityType='{}' in Meta TLS client cert Subject CN: '{}'", 37*0e373b53SMarco Kawajiri entityType, sslUser); 38*0e373b53SMarco Kawajiri return std::nullopt; 39*0e373b53SMarco Kawajiri } 40*0e373b53SMarco Kawajiri 41*0e373b53SMarco Kawajiri // Parse entity 42*0e373b53SMarco Kawajiri size_t slashIndex = sslUser.find('/'); 43*0e373b53SMarco Kawajiri std::string_view entity; 44*0e373b53SMarco Kawajiri if (slashIndex == std::string_view::npos) 45*0e373b53SMarco Kawajiri { 46*0e373b53SMarco Kawajiri // No '/' character, Subject CN is just '<entityType>:<entity>' 47*0e373b53SMarco Kawajiri entity = sslUser; 48*0e373b53SMarco Kawajiri } 49*0e373b53SMarco Kawajiri else 50*0e373b53SMarco Kawajiri { 51*0e373b53SMarco Kawajiri // Subject CN ends with /<hostname> 52*0e373b53SMarco Kawajiri entity = sslUser.substr(0, slashIndex); 53*0e373b53SMarco Kawajiri sslUser.remove_prefix(slashIndex + 1); 54*0e373b53SMarco Kawajiri 55*0e373b53SMarco Kawajiri if (entity.find_first_not_of( 56*0e373b53SMarco Kawajiri "abcdefghijklmnopqrstuvwxyz0123456789_-.") != std::string::npos) 57*0e373b53SMarco Kawajiri { 58*0e373b53SMarco Kawajiri BMCWEB_LOG_WARNING( 59*0e373b53SMarco Kawajiri "Invalid entity='{}' in Meta TLS client cert Subject CN: '{}'", 60*0e373b53SMarco Kawajiri entity, sslUser); 61*0e373b53SMarco Kawajiri return std::nullopt; 62*0e373b53SMarco Kawajiri } 63*0e373b53SMarco Kawajiri } 64*0e373b53SMarco Kawajiri 65*0e373b53SMarco Kawajiri if (entity.empty()) 66*0e373b53SMarco Kawajiri { 67*0e373b53SMarco Kawajiri BMCWEB_LOG_DEBUG("Invalid Meta TLS client cert Subject CN: '{}'", 68*0e373b53SMarco Kawajiri sslUser); 69*0e373b53SMarco Kawajiri return std::nullopt; 70*0e373b53SMarco Kawajiri } 71*0e373b53SMarco Kawajiri 72*0e373b53SMarco Kawajiri return entity; 73*0e373b53SMarco Kawajiri } 74