1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2020-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(internal_user). 9 10-include_lib("rabbit_common/include/rabbit.hrl"). 11 12-export([ 13 new/0, 14 new/1, 15 record_version_to_use/0, 16 fields/0, 17 fields/1, 18 upgrade/1, 19 upgrade_to/2, 20 pattern_match_all/0, 21 get_username/1, 22 get_password_hash/1, 23 get_tags/1, 24 get_hashing_algorithm/1, 25 get_limits/1, 26 create_user/3, 27 set_password_hash/3, 28 set_tags/2, 29 update_limits/3, 30 clear_limits/1 31]). 32 33-define(record_version, internal_user_v2). 34 35-type(username() :: binary()). 36 37-type(password_hash() :: binary()). 38 39-type internal_user() :: internal_user_v1:internal_user_v1() | internal_user_v2(). 40 41-record(internal_user, { 42 username :: username() | '_', 43 password_hash :: password_hash() | '_', 44 tags :: [atom()] | '_', 45 %% password hashing implementation module, 46 %% typically rabbit_password_hashing_* but can 47 %% come from a plugin 48 hashing_algorithm :: atom() | '_', 49 limits = #{} :: map() | '_'}). 50 51-type(internal_user_v2() :: 52 #internal_user{username :: username() | '_', 53 password_hash :: password_hash() | '_', 54 tags :: [atom()] | '_', 55 hashing_algorithm :: atom() | '_', 56 limits :: map()}). 57 58-type internal_user_pattern() :: internal_user_v1:internal_user_v1_pattern() | 59 internal_user_v2_pattern(). 60 61-type internal_user_v2_pattern() :: #internal_user{ 62 username :: username() | '_', 63 password_hash :: '_', 64 tags :: '_', 65 hashing_algorithm :: '_', 66 limits :: '_' 67 }. 68 69-export_type([username/0, 70 password_hash/0, 71 internal_user/0, 72 internal_user_v2/0, 73 internal_user_pattern/0, 74 internal_user_v2_pattern/0]). 75 76-spec new() -> internal_user(). 77new() -> 78 case record_version_to_use() of 79 ?record_version -> 80 #internal_user{ 81 username = <<"">>, 82 password_hash = <<"">>, 83 tags = [] 84 }; 85 _ -> 86 internal_user_v1:new() 87 end. 88 89-spec new(tuple()) -> internal_user(). 90new({hashing_algorithm, HashingAlgorithm}) -> 91 case record_version_to_use() of 92 ?record_version -> 93 #internal_user{ 94 username = <<"">>, 95 password_hash = <<"">>, 96 tags = [], 97 hashing_algorithm = HashingAlgorithm 98 }; 99 _ -> 100 internal_user_v1:new({hashing_algorithm, HashingAlgorithm}) 101 end; 102new({tags, Tags}) -> 103 case record_version_to_use() of 104 ?record_version -> 105 #internal_user{ 106 username = <<"">>, 107 password_hash = <<"">>, 108 tags = Tags 109 }; 110 _ -> 111 internal_user_v1:new({tags, Tags}) 112 end. 113 114-spec record_version_to_use() -> internal_user_v1 | internal_user_v2. 115record_version_to_use() -> 116 case rabbit_feature_flags:is_enabled(user_limits) of 117 true -> ?record_version; 118 false -> internal_user_v1:record_version_to_use() 119 end. 120 121-spec fields() -> list(). 122fields() -> 123 case record_version_to_use() of 124 ?record_version -> fields(?record_version); 125 _ -> internal_user_v1:fields() 126 end. 127 128-spec fields(atom()) -> list(). 129fields(?record_version) -> record_info(fields, internal_user); 130fields(Version) -> internal_user_v1:fields(Version). 131 132-spec upgrade(internal_user()) -> internal_user(). 133upgrade(#internal_user{} = User) -> User; 134upgrade(OldUser) -> upgrade_to(record_version_to_use(), OldUser). 135 136-spec upgrade_to 137(internal_user_v2, internal_user()) -> internal_user_v2(); 138(internal_user_v1, internal_user_v1:internal_user_v1()) -> internal_user_v1:internal_user_v1(). 139 140upgrade_to(?record_version, #internal_user{} = User) -> 141 User; 142upgrade_to(?record_version, OldUser) -> 143 Fields = erlang:tuple_to_list(OldUser) ++ [#{}], 144 #internal_user{} = erlang:list_to_tuple(Fields); 145upgrade_to(Version, OldUser) -> 146 internal_user_v1:upgrade_to(Version, OldUser). 147 148-spec pattern_match_all() -> internal_user_pattern(). 149pattern_match_all() -> 150 case record_version_to_use() of 151 ?record_version -> #internal_user{_ = '_'}; 152 _ -> internal_user_v1:pattern_match_all() 153 end. 154 155-spec get_username(internal_user()) -> username(). 156get_username(#internal_user{username = Value}) -> Value; 157get_username(User) -> internal_user_v1:get_username(User). 158 159-spec get_password_hash(internal_user()) -> password_hash(). 160get_password_hash(#internal_user{password_hash = Value}) -> Value; 161get_password_hash(User) -> internal_user_v1:get_password_hash(User). 162 163-spec get_tags(internal_user()) -> [atom()]. 164get_tags(#internal_user{tags = Value}) -> Value; 165get_tags(User) -> internal_user_v1:get_tags(User). 166 167-spec get_hashing_algorithm(internal_user()) -> atom(). 168get_hashing_algorithm(#internal_user{hashing_algorithm = Value}) -> Value; 169get_hashing_algorithm(User) -> internal_user_v1:get_hashing_algorithm(User). 170 171-spec get_limits(internal_user()) -> map(). 172get_limits(#internal_user{limits = Value}) -> Value; 173get_limits(User) -> internal_user_v1:get_limits(User). 174 175-spec create_user(username(), password_hash(), atom()) -> internal_user(). 176create_user(Username, PasswordHash, HashingMod) -> 177 case record_version_to_use() of 178 ?record_version -> 179 #internal_user{username = Username, 180 password_hash = PasswordHash, 181 tags = [], 182 hashing_algorithm = HashingMod, 183 limits = #{} 184 }; 185 _ -> 186 internal_user_v1:create_user(Username, PasswordHash, HashingMod) 187 end. 188 189-spec set_password_hash(internal_user(), password_hash(), atom()) -> internal_user(). 190set_password_hash(#internal_user{} = User, PasswordHash, HashingAlgorithm) -> 191 User#internal_user{password_hash = PasswordHash, 192 hashing_algorithm = HashingAlgorithm}; 193set_password_hash(User, PasswordHash, HashingAlgorithm) -> 194 internal_user_v1:set_password_hash(User, PasswordHash, HashingAlgorithm). 195 196-spec set_tags(internal_user(), [atom()]) -> internal_user(). 197set_tags(#internal_user{} = User, Tags) -> 198 User#internal_user{tags = Tags}; 199set_tags(User, Tags) -> 200 internal_user_v1:set_tags(User, Tags). 201 202-spec update_limits 203(add, internal_user(), map()) -> internal_user(); 204(remove, internal_user(), term()) -> internal_user(). 205update_limits(add, #internal_user{limits = Limits} = User, Term) -> 206 User#internal_user{limits = maps:merge(Limits, Term)}; 207update_limits(remove, #internal_user{limits = Limits} = User, LimitType) -> 208 User#internal_user{limits = maps:remove(LimitType, Limits)}; 209update_limits(Action, User, Term) -> 210 internal_user_v1:update_limits(Action, User, Term). 211 212-spec clear_limits(internal_user()) -> internal_user(). 213clear_limits(#internal_user{} = User) -> 214 User#internal_user{limits = #{}}; 215clear_limits(User) -> 216 internal_user_v1:clear_limits(User). 217