2
0

enrollmentkey.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. package logic
  2. import (
  3. b64 "encoding/base64"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "strings"
  8. "sync"
  9. "time"
  10. "github.com/google/uuid"
  11. "github.com/gravitl/netmaker/database"
  12. "github.com/gravitl/netmaker/models"
  13. "github.com/gravitl/netmaker/servercfg"
  14. "golang.org/x/exp/slices"
  15. )
  16. // EnrollmentErrors - struct for holding EnrollmentKey error messages
  17. var EnrollmentErrors = struct {
  18. InvalidCreate error
  19. NoKeyFound error
  20. InvalidKey error
  21. NoUsesRemaining error
  22. FailedToTokenize error
  23. FailedToDeTokenize error
  24. }{
  25. InvalidCreate: fmt.Errorf("failed to create enrollment key. paramters invalid"),
  26. NoKeyFound: fmt.Errorf("no enrollmentkey found"),
  27. InvalidKey: fmt.Errorf("invalid key provided"),
  28. NoUsesRemaining: fmt.Errorf("no uses remaining"),
  29. FailedToTokenize: fmt.Errorf("failed to tokenize"),
  30. FailedToDeTokenize: fmt.Errorf("failed to detokenize"),
  31. }
  32. var (
  33. enrollmentkeyCacheMutex = &sync.RWMutex{}
  34. enrollmentkeyCacheMap = make(map[string]models.EnrollmentKey)
  35. )
  36. // CreateEnrollmentKey - creates a new enrollment key in db
  37. func CreateEnrollmentKey(uses int, expiration time.Time, networks, tags []string, groups []models.TagID, unlimited bool, relay uuid.UUID, defaultKey, autoEgress bool) (*models.EnrollmentKey, error) {
  38. newKeyID, err := getUniqueEnrollmentID()
  39. if err != nil {
  40. return nil, err
  41. }
  42. k := &models.EnrollmentKey{
  43. Value: newKeyID,
  44. Expiration: time.Time{},
  45. UsesRemaining: 0,
  46. Unlimited: unlimited,
  47. Networks: []string{},
  48. Tags: []string{},
  49. Type: models.Undefined,
  50. Relay: relay,
  51. Groups: groups,
  52. Default: defaultKey,
  53. AutoEgress: autoEgress,
  54. }
  55. if uses > 0 {
  56. k.UsesRemaining = uses
  57. k.Type = models.Uses
  58. } else if !expiration.IsZero() {
  59. k.Expiration = expiration
  60. k.Type = models.TimeExpiration
  61. } else if k.Unlimited {
  62. k.Type = models.Unlimited
  63. }
  64. if len(networks) > 0 {
  65. k.Networks = networks
  66. }
  67. if len(tags) > 0 {
  68. k.Tags = tags
  69. }
  70. if err := k.Validate(); err != nil {
  71. return nil, err
  72. }
  73. if relay != uuid.Nil {
  74. relayNode, err := GetNodeByID(relay.String())
  75. if err != nil {
  76. return nil, err
  77. }
  78. if !slices.Contains(k.Networks, relayNode.Network) {
  79. return nil, errors.New("relay node not in key's networks")
  80. }
  81. if !relayNode.IsRelay {
  82. return nil, errors.New("relay node is not a relay")
  83. }
  84. }
  85. if err = upsertEnrollmentKey(k); err != nil {
  86. return nil, err
  87. }
  88. return k, nil
  89. }
  90. // UpdateEnrollmentKey - updates an existing enrollment key's associated relay
  91. func UpdateEnrollmentKey(keyId string, relayId uuid.UUID, groups []models.TagID) (*models.EnrollmentKey, error) {
  92. key, err := GetEnrollmentKey(keyId)
  93. if err != nil {
  94. return nil, err
  95. }
  96. if relayId != uuid.Nil {
  97. relayNode, err := GetNodeByID(relayId.String())
  98. if err != nil {
  99. return nil, err
  100. }
  101. if !slices.Contains(key.Networks, relayNode.Network) {
  102. return nil, errors.New("relay node not in key's networks")
  103. }
  104. if !relayNode.IsRelay {
  105. return nil, errors.New("relay node is not a relay")
  106. }
  107. }
  108. key.Relay = relayId
  109. key.Groups = groups
  110. if err = upsertEnrollmentKey(&key); err != nil {
  111. return nil, err
  112. }
  113. return &key, nil
  114. }
  115. // GetAllEnrollmentKeys - fetches all enrollment keys from DB
  116. func GetAllEnrollmentKeys() ([]models.EnrollmentKey, error) {
  117. currentKeys, err := getEnrollmentKeysMap()
  118. if err != nil {
  119. return nil, err
  120. }
  121. var currentKeysList = []models.EnrollmentKey{}
  122. for k := range currentKeys {
  123. currentKeysList = append(currentKeysList, currentKeys[k])
  124. }
  125. return currentKeysList, nil
  126. }
  127. // GetEnrollmentKey - fetches a single enrollment key
  128. // returns nil and error if not found
  129. func GetEnrollmentKey(value string) (key models.EnrollmentKey, err error) {
  130. currentKeys, err := getEnrollmentKeysMap()
  131. if err != nil {
  132. return key, err
  133. }
  134. if key, ok := currentKeys[value]; ok {
  135. return key, nil
  136. }
  137. return key, EnrollmentErrors.NoKeyFound
  138. }
  139. func deleteEnrollmentkeyFromCache(key string) {
  140. enrollmentkeyCacheMutex.Lock()
  141. delete(enrollmentkeyCacheMap, key)
  142. enrollmentkeyCacheMutex.Unlock()
  143. }
  144. // DeleteEnrollmentKey - delete's a given enrollment key by value
  145. func DeleteEnrollmentKey(value string, force bool) error {
  146. key, err := GetEnrollmentKey(value)
  147. if err != nil {
  148. return err
  149. }
  150. if key.Default && !force {
  151. return errors.New("cannot delete default network key")
  152. }
  153. err = database.DeleteRecord(database.ENROLLMENT_KEYS_TABLE_NAME, value)
  154. if err == nil {
  155. if servercfg.CacheEnabled() {
  156. deleteEnrollmentkeyFromCache(value)
  157. }
  158. }
  159. return err
  160. }
  161. // TryToUseEnrollmentKey - checks first if key can be decremented
  162. // returns true if it is decremented or isvalid
  163. func TryToUseEnrollmentKey(k *models.EnrollmentKey) bool {
  164. key, err := decrementEnrollmentKey(k.Value)
  165. if err != nil {
  166. if errors.Is(err, EnrollmentErrors.NoUsesRemaining) {
  167. return k.IsValid()
  168. }
  169. } else {
  170. k.UsesRemaining = key.UsesRemaining
  171. return true
  172. }
  173. return false
  174. }
  175. // Tokenize - tokenizes an enrollment key to be used via registration
  176. // and attaches it to the Token field on the struct
  177. func Tokenize(k *models.EnrollmentKey, serverAddr string) error {
  178. if len(serverAddr) == 0 || k == nil {
  179. return EnrollmentErrors.FailedToTokenize
  180. }
  181. newToken := models.EnrollmentToken{
  182. Server: serverAddr,
  183. Value: k.Value,
  184. }
  185. data, err := json.Marshal(&newToken)
  186. if err != nil {
  187. return err
  188. }
  189. k.Token = b64.StdEncoding.EncodeToString(data)
  190. return nil
  191. }
  192. // DeTokenize - detokenizes a base64 encoded string
  193. // and finds the associated enrollment key
  194. func DeTokenize(b64Token string) (*models.EnrollmentKey, error) {
  195. if len(b64Token) == 0 {
  196. return nil, EnrollmentErrors.FailedToDeTokenize
  197. }
  198. tokenData, err := b64.StdEncoding.DecodeString(b64Token)
  199. if err != nil {
  200. return nil, err
  201. }
  202. var newToken models.EnrollmentToken
  203. err = json.Unmarshal(tokenData, &newToken)
  204. if err != nil {
  205. return nil, err
  206. }
  207. k, err := GetEnrollmentKey(newToken.Value)
  208. if err != nil {
  209. return nil, err
  210. }
  211. return &k, nil
  212. }
  213. // == private ==
  214. // decrementEnrollmentKey - decrements the uses on a key if above 0 remaining
  215. func decrementEnrollmentKey(value string) (*models.EnrollmentKey, error) {
  216. k, err := GetEnrollmentKey(value)
  217. if err != nil {
  218. return nil, err
  219. }
  220. if k.UsesRemaining == 0 {
  221. return nil, EnrollmentErrors.NoUsesRemaining
  222. }
  223. k.UsesRemaining = k.UsesRemaining - 1
  224. if err = upsertEnrollmentKey(&k); err != nil {
  225. return nil, err
  226. }
  227. return &k, nil
  228. }
  229. func upsertEnrollmentKey(k *models.EnrollmentKey) error {
  230. if k == nil {
  231. return EnrollmentErrors.InvalidKey
  232. }
  233. data, err := json.Marshal(k)
  234. if err != nil {
  235. return err
  236. }
  237. err = database.Insert(k.Value, string(data), database.ENROLLMENT_KEYS_TABLE_NAME)
  238. if err == nil {
  239. if servercfg.CacheEnabled() {
  240. storeEnrollmentkeyInCache(k.Value, *k)
  241. }
  242. }
  243. return nil
  244. }
  245. func getUniqueEnrollmentID() (string, error) {
  246. currentKeys, err := getEnrollmentKeysMap()
  247. if err != nil {
  248. return "", err
  249. }
  250. newID := RandomString(models.EnrollmentKeyLength)
  251. for _, ok := currentKeys[newID]; ok; {
  252. newID = RandomString(models.EnrollmentKeyLength)
  253. }
  254. return newID, nil
  255. }
  256. func getEnrollmentkeysFromCache() map[string]models.EnrollmentKey {
  257. return enrollmentkeyCacheMap
  258. }
  259. func storeEnrollmentkeyInCache(key string, enrollmentkey models.EnrollmentKey) {
  260. enrollmentkeyCacheMutex.Lock()
  261. enrollmentkeyCacheMap[key] = enrollmentkey
  262. enrollmentkeyCacheMutex.Unlock()
  263. }
  264. func getEnrollmentKeysMap() (map[string]models.EnrollmentKey, error) {
  265. if servercfg.CacheEnabled() {
  266. keys := getEnrollmentkeysFromCache()
  267. if len(keys) != 0 {
  268. return keys, nil
  269. }
  270. }
  271. records, err := database.FetchRecords(database.ENROLLMENT_KEYS_TABLE_NAME)
  272. if err != nil {
  273. if !database.IsEmptyRecord(err) {
  274. return nil, err
  275. }
  276. }
  277. if records == nil {
  278. records = make(map[string]string)
  279. }
  280. currentKeys := make(map[string]models.EnrollmentKey, 0)
  281. if len(records) > 0 {
  282. for k := range records {
  283. var currentKey models.EnrollmentKey
  284. if err = json.Unmarshal([]byte(records[k]), &currentKey); err != nil {
  285. continue
  286. }
  287. currentKeys[k] = currentKey
  288. if servercfg.CacheEnabled() {
  289. storeEnrollmentkeyInCache(currentKey.Value, currentKey)
  290. }
  291. }
  292. }
  293. return currentKeys, nil
  294. }
  295. func RemoveTagFromEnrollmentKeys(deletedTagID models.TagID) {
  296. keys, _ := GetAllEnrollmentKeys()
  297. for _, key := range keys {
  298. newTags := []models.TagID{}
  299. update := false
  300. for _, tagID := range key.Groups {
  301. if tagID == deletedTagID {
  302. update = true
  303. continue
  304. }
  305. newTags = append(newTags, tagID)
  306. }
  307. if update {
  308. key.Groups = newTags
  309. upsertEnrollmentKey(&key)
  310. }
  311. }
  312. }
  313. func UnlinkNetworkAndTagsFromEnrollmentKeys(network string, delete bool) error {
  314. keys, err := GetAllEnrollmentKeys()
  315. if err != nil {
  316. return fmt.Errorf("failed to retrieve keys: %w", err)
  317. }
  318. var errs []error
  319. for _, key := range keys {
  320. newNetworks := []string{}
  321. newTags := []models.TagID{}
  322. update := false
  323. // Check and update networks
  324. for _, net := range key.Networks {
  325. if net == network {
  326. update = true
  327. continue
  328. }
  329. newNetworks = append(newNetworks, net)
  330. }
  331. // Check and update tags
  332. for _, tag := range key.Groups {
  333. tagParts := strings.Split(tag.String(), ".")
  334. if len(tagParts) == 0 {
  335. continue
  336. }
  337. tagNetwork := tagParts[0]
  338. if tagNetwork == network {
  339. update = true
  340. continue
  341. }
  342. newTags = append(newTags, tag)
  343. }
  344. if update && len(newNetworks) == 0 && delete {
  345. if err := DeleteEnrollmentKey(key.Value, true); err != nil {
  346. errs = append(errs, fmt.Errorf("failed to delete key %s: %w", key.Value, err))
  347. }
  348. continue
  349. }
  350. if update {
  351. key.Networks = newNetworks
  352. key.Groups = newTags
  353. if err := upsertEnrollmentKey(&key); err != nil {
  354. errs = append(errs, fmt.Errorf("failed to update key %s: %w", key.Value, err))
  355. }
  356. }
  357. }
  358. if len(errs) > 0 {
  359. return fmt.Errorf("errors unlinking network/tags from keys: %v", errs)
  360. }
  361. return nil
  362. }