blob: 5e55db8e280d6d1cf60f9a3cb1e79d5ecf9656fd [file] [log] [blame]
Marco Kawajiri0e373b52023-10-31 13:36:58 -07001#pragma once
2
3#include "logging.hpp"
4
5#include <format>
6#include <optional>
7#include <string>
8#include <string_view>
9
10inline 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}