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