From 01dd4696cf6379dc9f156544489db22c37cac2da Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Thu, 19 Sep 2024 17:40:28 +0300 Subject: [PATCH] Fix flaky nats integration test Was failing on the Jetstream JWTAuth case with error: nats: API error: code=500 err_code=10047 description=insufficient storage resources available The issue was with the previously generated credentials. Generated them again and added the program used as a comment at the end of the file for future reference" --- data/conf/samples/ers_nats/cgrates.json | 64 +++--- ers/nats_it_test.go | 255 +++++++++++++++++++++--- 2 files changed, 255 insertions(+), 64 deletions(-) diff --git a/data/conf/samples/ers_nats/cgrates.json b/data/conf/samples/ers_nats/cgrates.json index 3c424d439..68616eb0f 100644 --- a/data/conf/samples/ers_nats/cgrates.json +++ b/data/conf/samples/ers_nats/cgrates.json @@ -28,53 +28,53 @@ ] }, -"ers": { - "enabled": true, +"ers": { + "enabled": true, "sessions_conns":[], - "ees_conns": ["*internal"], + "ees_conns": ["*internal"], "readers": [ { - "id": "nats_reader1", - "type": "*nats_json_map", - "source_path": "nats://127.0.0.1:4222", + "id": "nats_reader1", + "type": "*nats_json_map", + "source_path": "nats://127.0.0.1:4222", "processed_path": "nats://127.0.0.1:4222", - "ees_success_ids": ["nats_processed"], + "ees_success_ids": ["nats_processed"], "opts": { - "natsJetStream": true, - "natsConsumerName": "cgrates", - "natsStreamName": "stream", - "natsSubject": "cgrates_cdrs", - "natsQueueID": "queue", - "natsJetStreamMaxWait": "5s" + "natsJetStream": true, + "natsConsumerName": "cgrates", + "natsStreamName": "stream", + "natsSubject": "cgrates_cdrs", + "natsQueueID": "queue", + "natsJetStreamMaxWait": "5s" }, - "flags": ["*dryrun"], - "fields":[ + "flags": ["*dryrun"], + "fields":[ {"tag": "cdr_template", "type": "*template", "value": "cdr_template"} ] }, { - "id": "nats_reader2", - "type": "*nats_json_map", - "source_path": "nats://127.0.0.1:4222", - "processed_path": "nats://127.0.0.1:4222", - "ees_success_ids": ["nats_processed"], + "id": "nats_reader2", + "type": "*nats_json_map", + "source_path": "nats://127.0.0.1:4222", + "processed_path": "nats://127.0.0.1:4222", + "ees_success_ids": ["nats_processed"], "opts": { - "natsJetStream": true, - "natsConsumerName": "cgrates", - "natsStreamName": "stream", - "natsSubject": "cgrates_cdrs", - "natsQueueID": "queue", - "natsJetStreamMaxWait": "5s" + "natsJetStream": true, + "natsConsumerName": "cgrates", + "natsStreamName": "stream", + "natsSubject": "cgrates_cdrs", + "natsQueueID": "queue", + "natsJetStreamMaxWait": "5s" }, - "flags": ["*dryrun"], - "fields":[ + "flags": ["*dryrun"], + "fields":[ {"tag": "cdr_template", "type": "*template", "value": "cdr_template"} ] } ] }, - - + + "templates": { "cdr_template": [ {"tag": "Account", "path": "*cgreq.Account", "type": "*variable", "value": "~*req.Account", "mandatory": true}, @@ -82,5 +82,5 @@ {"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable", "value": "~*req.Destination", "mandatory": true} ] } - -} \ No newline at end of file + +} diff --git a/ers/nats_it_test.go b/ers/nats_it_test.go index 4a322e1fe..2266cc6a4 100644 --- a/ers/nats_it_test.go +++ b/ers/nats_it_test.go @@ -1,4 +1,4 @@ -//go:build flaky +//go:build integration /* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments @@ -157,28 +157,28 @@ var natsCfg string = `{ ] }, -"ers": { - "enabled": true, +"ers": { + "enabled": true, "sessions_conns":[], - "ees_conns": ["*internal"], + "ees_conns": ["*internal"], "readers": [ { - "id": "nats_reader1", - "type": "*nats_json_map", - "source_path": "%s", - "ees_success_ids": ["nats_processed"], - "flags": ["*dryrun"], + "id": "nats_reader1", + "type": "*nats_json_map", + "source_path": "%s", + "ees_success_ids": ["nats_processed"], + "flags": ["*dryrun"], "opts": { - %s + %s }, - "fields":[ + "fields":[ {"tag": "CGRID", "type": "*variable", "value": "~*req.CGRID", "path": "*cgreq.CGRID"}, {"tag": "readerId", "type": "*variable", "value": "~*vars.*readerID", "path": "*cgreq.ReaderID"}, ] } ] } - + }` func TestNatsNormalTT(t *testing.T) { @@ -207,7 +207,7 @@ func TestNatsNormalTT(t *testing.T) { // JWTFile setup baseJWTPath := t.TempDir() - jwtFilePath := path.Join(baseJWTPath, "jwt.txt") + jwtFilePath := path.Join(baseJWTPath, "u.creds") if err := os.WriteFile(jwtFilePath, []byte(`-----BEGIN NATS USER JWT----- eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJETFRGNFpLVVdNNFRPRkVNQko0UEUzTVFFVlhIUkJJN0xZNDdZNEMzNTNMWlJKSU5CUkJRIiwiaWF0IjoxNjI0ODg1NzMwLCJpc3MiOiJBQVlKRFZMWkdXTjdZM0ZCUENWWENSVlFaREZNWUdIVTRZWExHU1hYN1UyNTRLSDVTQzNSNVFLTSIsIm5hbWUiOiJ1c2VyIiwic3ViIjoiVUQzQkdXSUJQVTNDV0w0SE9VVTRWSkVRV1RVQVNBRUc2T0ozWEhNM0VFSk5BMlBBM1VWTllUWk4iLCJuYXRzIjp7InB1YiI6e30sInN1YiI6e30sInN1YnMiOi0xLCJkYXRhIjotMSwicGF5bG9hZCI6LTEsInR5cGUiOiJ1c2VyIiwidmVyc2lvbiI6Mn19.YmFL5nRMkEOXe77sQJPPRv_vwi89tzhVVl0AVjE4sXWyoWIHiCepNw28DbpJ0p_MlT8Qf0SY2cjAhIm-Qi7lDw ------END NATS USER JWT------ @@ -223,7 +223,7 @@ SUADIH32XQYWC2MI2YGM4AUQ3NMKZSZ5V2BZXQ237XXMLO7FFHDF5CTUDE *************************************************************`), 0664); err != nil { t.Fatal(err) } - jwtCfgPath := path.Join(baseJWTPath, "nats.cfg") + jwtCfgPath := path.Join(baseJWTPath, "resolver.conf") if err := os.WriteFile(jwtCfgPath, []byte(`// Operator "memory" operator: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJFRk5ERUdSNU1aUEw1VElQTFVKMlNMTFdZV0VDU0NJSEhVU1lISE5IR1BZVUpaWE5XUlNRIiwiaWF0IjoxNjI0ODc1NzYwLCJpc3MiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hbWUiOiJtZW1vcnkiLCJzdWIiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hdHMiOnsidHlwZSI6Im9wZXJhdG9yIiwidmVyc2lvbiI6Mn19.MZfwcw5j6zY8SfFQppGIa3VjYYZK2_n1kV16Nk5jVCgwS8dKWzRQK_XjFYWwQ15Cq9YY73jcTA6LO0DmQGsdBA @@ -382,11 +382,9 @@ func TestNatsJetStreamTT(t *testing.T) { // JWTFile setup baseJWTPath := t.TempDir() - // baseJWTPath := "/tmp/natsCfg3" - // os.Mkdir("/tmp/natsCfg3", 0644) - jwtFilePath := path.Join(baseJWTPath, "jwt.txt") + jwtFilePath := path.Join(baseJWTPath, "u.creds") if err := os.WriteFile(jwtFilePath, []byte(`-----BEGIN NATS USER JWT----- -eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJXTUUyUkhMWEU1R0FZS0hITk5aNkhLSDQ2Q0VSUFNEUExPN1BMT0ZEWTZaNUdZM09aVkFRIiwiaWF0IjoxNjI0OTUzNTE5LCJpc3MiOiJBQVlKRFZMWkdXTjdZM0ZCUENWWENSVlFaREZNWUdIVTRZWExHU1hYN1UyNTRLSDVTQzNSNVFLTSIsIm5hbWUiOiJ1c2VyMiIsInN1YiI6IlVERVJVRElMMlZORVNKUzVGNUpDQVJHWUNSUVM1M0NWSUVBSllHU0hFR0dZSEI2R01BQ1AzM1VDIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9LCJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJ0eXBlIjoidXNlciIsInZlcnNpb24iOjJ9fQ.YitrKhIlU45Q1m6A_HFsaxDgUUiIyjLJuHNKnG1cjzj5H6n697Iv3pDsIZVTh6pBYROg1aRV42bD3PpEZna2AA +eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJIMkwzWEtSTVoyMklDSFBGSDRXQzM1U0hLRVY3RVZUTEJERlpESVhTN0xOWEhCNkhUV0ZBIiwiaWF0IjoxNzI2NzUyOTAzLCJpc3MiOiJBQktCWlJVVFY0M1NZN1E2VlA3TVBYTldBQzdOTVZCUzJGUEpRMzZHQ1dWNVZIRzVCVVlFNTRGSSIsInN1YiI6IlVCSUtHTlRPRFJPTU8yWEdZTk5TQ1hQNUNLSlBUSVRWUTY1TjdZVEZQWVFKNFdFWVY3T0xPTkE1IiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9LCJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJpc3N1ZXJfYWNjb3VudCI6IkFCVFZITzJNUkVOQlcyTk81N0tXSzZMWENaU0g0M09IUEtYRFlHWEJENlFZWlFDSkhGRURNNVFYIiwidHlwZSI6InVzZXIiLCJ2ZXJzaW9uIjoyfX0.rIFeciJthv_V4OfRc1wQXxk7-E3Wa6-87suJI_sn808Az7psEdvFagNosCqgdGd_d7AUDhY2eCipcIEZxnPeBA ------END NATS USER JWT------ ************************* IMPORTANT ************************* @@ -394,28 +392,22 @@ NKEY Seed printed below can be used to sign and prove identity. NKEYs are sensitive and should be treated as secrets. -----BEGIN USER NKEY SEED----- -SUAGM22ETPOJNZGYSGJL3HRLZ6R35FSVOYNINYN5Z5UPLP5K4SQJ753WU4 +SUAD3BD2VMG6RJZVODS5BKYHOY6HGM7U5VDFYEEDHXIQXBX5R7RMKVQS4Y ------END USER NKEY SEED------ *************************************************************`), 0664); err != nil { t.Fatal(err) } - jwtCfgPath := path.Join(baseJWTPath, "nats.cfg") - if err := os.WriteFile(jwtCfgPath, []byte(`// Operator "memory" -operator: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJFRk5ERUdSNU1aUEw1VElQTFVKMlNMTFdZV0VDU0NJSEhVU1lISE5IR1BZVUpaWE5XUlNRIiwiaWF0IjoxNjI0ODc1NzYwLCJpc3MiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hbWUiOiJtZW1vcnkiLCJzdWIiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hdHMiOnsidHlwZSI6Im9wZXJhdG9yIiwidmVyc2lvbiI6Mn19.MZfwcw5j6zY8SfFQppGIa3VjYYZK2_n1kV16Nk5jVCgwS8dKWzRQK_XjFYWwQ15Cq9YY73jcTA6LO0DmQGsdBA + jwtCfgPath := path.Join(baseJWTPath, "resolver.conf") + if err := os.WriteFile(jwtCfgPath, []byte(`operator: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJQRVBMTFM3WFQyUzQ2NUZIS0JDSjdTNDdWS1VPRjJEVFhWRE9QVzZTWjY3R0JTU0I3SllBIiwiaWF0IjoxNzI2NzUyOTAzLCJpc3MiOiJPQzZJRFFQVTZJNFFOTVZYUEpSR1RSVFpHRFNTSEVSMzVMSkQ3V0k3RlJEUUpPT1ZUUjVKRjczWiIsIm5hbWUiOiJPIiwic3ViIjoiT0M2SURRUFU2STRRTk1WWFBKUkdUUlRaR0RTU0hFUjM1TEpEN1dJN0ZSRFFKT09WVFI1SkY3M1oiLCJuYXRzIjp7InNpZ25pbmdfa2V5cyI6WyJPQUdPWkNFRjNWR1FFV1RRTkFZTllJRFpFREVZSU03WDI3S0xKQzdaU1c3WDVQSjZJSllEWEgyUyJdLCJ0eXBlIjoib3BlcmF0b3IiLCJ2ZXJzaW9uIjoyfX0.KS5aRNmSKIcIDrEIZvpLPgmrwKGMExSTOnsp579ihwqRLFt5ZrDXEl8I81F-lgvRGZ0_yX4fUIQ9-J4trZDkDw + +system_account: ADXMVBEVF2FHZTELG3CMW4VT4WRN6JK3SSXSS34G77BUX7YD6KWU2GMI resolver: MEMORY - resolver_preload: { - // Account "js" - AAFIBB6C56ROU5XRVJLJYR3BTGGYK3HJGHEHQV7L7QZMTT3ZRBLHBS7F: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJQNEZOWllRQkNKWERZT09ITzRNVU5BQTRHR0w2UTVIRkxKQUJXVEc3WVFIRFVNUVlHUldRIiwiaWF0IjoxNjI0OTU0MjQ0LCJpc3MiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hbWUiOiJqcyIsInN1YiI6IkFBRklCQjZDNTZST1U1WFJWSkxKWVIzQlRHR1lLM0hKR0hFSFFWN0w3UVpNVFQzWlJCTEhCUzdGIiwibmF0cyI6eyJsaW1pdHMiOnsic3VicyI6LTEsImRhdGEiOi0xLCJwYXlsb2FkIjotMSwiaW1wb3J0cyI6LTEsImV4cG9ydHMiOi0xLCJ3aWxkY2FyZHMiOnRydWUsImNvbm4iOi0xLCJsZWFmIjotMX0sImRlZmF1bHRfcGVybWlzc2lvbnMiOnsicHViIjp7fSwic3ViIjp7fX0sInR5cGUiOiJhY2NvdW50IiwidmVyc2lvbiI6Mn19.tGaVbpNXuSFxk3RDxicbi62nupiTv_-vTgps0t-LmvxKoNuzjvrnhyARwdh3qknMP54pDqzlUfldqubmEYLFBg - - // Account "account" - AAYJDVLZGWN7Y3FBPCVXCRVQZDFMYGHU4YXLGSXX7U254KH5SC3R5QKM: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJTUkVHMkdLUVg1RlJKQ0lTUlFITVlNUU9CU09DSkRYMjVaUUpGTllDMkxMQkZBRlNOQU9BIiwiaWF0IjoxNjI0OTUzNzIzLCJpc3MiOiJPQ0VSUlQ2WFNEQ1dBWTNFWVNTTjQ2UUxGQko3RFJHNTIzU1hIMkg0UjQ3WFZVWFYyUlJCSVNMSyIsIm5hbWUiOiJhY2NvdW50Iiwic3ViIjoiQUFZSkRWTFpHV043WTNGQlBDVlhDUlZRWkRGTVlHSFU0WVhMR1NYWDdVMjU0S0g1U0MzUjVRS00iLCJuYXRzIjp7ImxpbWl0cyI6eyJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJpbXBvcnRzIjotMSwiZXhwb3J0cyI6LTEsIndpbGRjYXJkcyI6dHJ1ZSwiY29ubiI6LTEsImxlYWYiOi0xLCJtZW1fc3RvcmFnZSI6LTEsInN0cmVhbXMiOi0xLCJjb25zdW1lciI6LTF9LCJkZWZhdWx0X3Blcm1pc3Npb25zIjp7InB1YiI6e30sInN1YiI6e319LCJ0eXBlIjoiYWNjb3VudCIsInZlcnNpb24iOjJ9fQ.rcOqLmWL77kgoDS4GPK5qs-rpG1mQCkQ5FoCzT3VGqsIXNdpn72d38jbCeV40_6l8dI49IRtRHySv8k7VwaaAA - -} -system_account:AAFIBB6C56ROU5XRVJLJYR3BTGGYK3HJGHEHQV7L7QZMTT3ZRBLHBS7F -`), 0664); err != nil { + ADXMVBEVF2FHZTELG3CMW4VT4WRN6JK3SSXSS34G77BUX7YD6KWU2GMI: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiI0UzJRVU1JWDdGTjZJR0lUM0xTWERMN1ZaQTVJQlUyNjJFTkY3WTZGR1JMNDJWNE5YUkdBIiwiaWF0IjoxNzI2NzUyOTAzLCJpc3MiOiJPQUdPWkNFRjNWR1FFV1RRTkFZTllJRFpFREVZSU03WDI3S0xKQzdaU1c3WDVQSjZJSllEWEgyUyIsIm5hbWUiOiJTWVMiLCJzdWIiOiJBRFhNVkJFVkYyRkhaVEVMRzNDTVc0VlQ0V1JONkpLM1NTWFNTMzRHNzdCVVg3WUQ2S1dVMkdNSSIsIm5hdHMiOnsibGltaXRzIjp7InN1YnMiOi0xLCJkYXRhIjotMSwicGF5bG9hZCI6LTEsImltcG9ydHMiOi0xLCJleHBvcnRzIjotMSwid2lsZGNhcmRzIjp0cnVlLCJjb25uIjotMSwibGVhZiI6LTF9LCJkZWZhdWx0X3Blcm1pc3Npb25zIjp7InB1YiI6eyJhbGxvdyI6WyIkU1lTLlx1MDAzZSJdfSwic3ViIjp7ImFsbG93IjpbIiRTWVMuXHUwMDNlIl19fSwiYXV0aG9yaXphdGlvbiI6e30sInR5cGUiOiJhY2NvdW50IiwidmVyc2lvbiI6Mn19.nZFNLl_sfCsaX2jTPFkCsHRbDNt0WGlpR0tx3K8J9KP8Ds8VmiQl7OvEmYjZflVKDVJgXvIwICIT-aY56klsAg + ABTVHO2MRENBW2NO57KWK6LXCZSH43OHPKXDYGXBD6QYZQCJHFEDM5QX: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJKWFZETkU2NVhITFg0Qk03M0EzUDNIWkFZT0QyTFlZUUc3SElIMjQ1QUlHN1Y0NVBVSTRBIiwiaWF0IjoxNzI2NzUyOTAzLCJpc3MiOiJPQUdPWkNFRjNWR1FFV1RRTkFZTllJRFpFREVZSU03WDI3S0xKQzdaU1c3WDVQSjZJSllEWEgyUyIsIm5hbWUiOiJBIiwic3ViIjoiQUJUVkhPMk1SRU5CVzJOTzU3S1dLNkxYQ1pTSDQzT0hQS1hEWUdYQkQ2UVlaUUNKSEZFRE01UVgiLCJuYXRzIjp7ImxpbWl0cyI6eyJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJpbXBvcnRzIjotMSwiZXhwb3J0cyI6LTEsIndpbGRjYXJkcyI6dHJ1ZSwiY29ubiI6LTEsImxlYWYiOi0xLCJtZW1fc3RvcmFnZSI6LTEsImRpc2tfc3RvcmFnZSI6LTEsInN0cmVhbXMiOi0xLCJjb25zdW1lciI6LTF9LCJzaWduaW5nX2tleXMiOlsiQUJLQlpSVVRWNDNTWTdRNlZQN01QWE5XQUM3Tk1WQlMyRlBKUTM2R0NXVjVWSEc1QlVZRTU0RkkiXSwiZGVmYXVsdF9wZXJtaXNzaW9ucyI6eyJwdWIiOnt9LCJzdWIiOnt9fSwiYXV0aG9yaXphdGlvbiI6e30sInR5cGUiOiJhY2NvdW50IiwidmVyc2lvbiI6Mn19.GWvAWjlECPNT5afsc96NVIEOJLFQi5fL9gBEzY4-z7mGyJN41qjJpx7l_LvLb8icToW2nca81J9NFwT5yf-NAA +}`), 0664); err != nil { t.Fatal(err) } @@ -552,3 +544,202 @@ system_account:AAFIBB6C56ROU5XRVJLJYR3BTGGYK3HJGHEHQV7L7QZMTT3ZRBLHBS7F }) } } + +/* + +In order to generate the resolver.conf and u.creds for the jetstream test, run the following: + +package main + +import ( + "fmt" + "log" + "os" + "path" + + "github.com/nats-io/jwt/v2" + "github.com/nats-io/nkeys" +) + +func main() { + // create an operator key pair (private key) + okp, err := nkeys.CreateOperator() + if err != nil { + log.Fatal(err) + } + // extract the public key + opk, err := okp.PublicKey() + if err != nil { + log.Fatal(err) + } + + // create an operator claim using the public key for the identifier + oc := jwt.NewOperatorClaims(opk) + oc.Name = "O" + // add an operator signing key to sign accounts + oskp, err := nkeys.CreateOperator() + if err != nil { + log.Fatal(err) + } + // get the public key for the signing key + ospk, err := oskp.PublicKey() + if err != nil { + log.Fatal(err) + } + // add the signing key to the operator - this makes any account + // issued by the signing key to be valid for the operator + oc.SigningKeys.Add(ospk) + + // self-sign the operator JWT - the operator trusts itself + operatorJWT, err := oc.Encode(okp) + if err != nil { + log.Fatal(err) + } + + // Create system account + sysAkp, err := nkeys.CreateAccount() + if err != nil { + log.Fatal(err) + } + sysApk, err := sysAkp.PublicKey() + if err != nil { + log.Fatal(err) + } + sysAc := jwt.NewAccountClaims(sysApk) + sysAc.Name = "SYS" + // Add necessary system permissions + sysAc.DefaultPermissions.Pub.Allow.Add("$SYS.>") + sysAc.DefaultPermissions.Sub.Allow.Add("$SYS.>") + sysAccountJWT, err := sysAc.Encode(oskp) + if err != nil { + log.Fatal(err) + } + + // create an account keypair + akp, err := nkeys.CreateAccount() + if err != nil { + log.Fatal(err) + } + // extract the public key for the account + apk, err := akp.PublicKey() + if err != nil { + log.Fatal(err) + } + // create the claim for the account using the public key of the account + ac := jwt.NewAccountClaims(apk) + ac.Name = "A" + + // enable jetstream for account + ac.Limits.JetStreamLimits = jwt.JetStreamLimits{ + MemoryStorage: -1, + DiskStorage: -1, + Streams: -1, + Consumer: -1, + } + + // create a signing key that we can use for issuing users + askp, err := nkeys.CreateAccount() + if err != nil { + log.Fatal(err) + } + // extract the public key + aspk, err := askp.PublicKey() + if err != nil { + log.Fatal(err) + } + // add the signing key (public) to the account + ac.SigningKeys.Add(aspk) + + // now we could encode an issue the account using the operator + // key that we generated above, but this will illustrate that + // the account could be self-signed, and given to the operator + // who can then re-sign it + accountJWT, err := ac.Encode(akp) + if err != nil { + log.Fatal(err) + } + + // the operator would decode the provided token, if the token + // is not self-signed or signed by an operator or tampered with + // the decoding would fail + ac, err = jwt.DecodeAccountClaims(accountJWT) + if err != nil { + log.Fatal(err) + } + // here the operator is going to use its private signing key to + // re-issue the account + accountJWT, err = ac.Encode(oskp) + if err != nil { + log.Fatal(err) + } + + // now back to the account, the account can issue users + // need not be known to the operator - the users are trusted + // because they will be signed by the account. The server will + // look up the account get a list of keys the account has and + // verify that the user was issued by one of those keys + ukp, err := nkeys.CreateUser() + if err != nil { + log.Fatal(err) + } + upk, err := ukp.PublicKey() + if err != nil { + log.Fatal(err) + } + uc := jwt.NewUserClaims(upk) + // since the jwt will be issued by a signing key, the issuer account + // must be set to the public ID of the account + uc.IssuerAccount = apk + userJwt, err := uc.Encode(askp) + if err != nil { + log.Fatal(err) + } + // the seed is a version of the keypair that is stored as text + useed, err := ukp.Seed() + if err != nil { + log.Fatal(err) + } + // generate a creds formatted file that can be used by a NATS client + creds, err := jwt.FormatUserConfig(userJwt, useed) + if err != nil { + log.Fatal(err) + } + + // now we are going to put it together into something that can be run + // we create a directory to store the server configuration, the creds + // file and a small go program that uses the creds file + dir, err := os.MkdirTemp(os.TempDir(), "jwt_example") + if err != nil { + log.Fatal(err) + } + // print where we generated the file + fmt.Printf("cfg path: %s\n", dir) + + // we are generating a memory resolver server configuration + // it lists the operator and all account jwts the server should + // know about + resolver := fmt.Sprintf(`operator: %s + +system_account: %s + +resolver: MEMORY +resolver_preload: { + %s: %s + %s: %s +} + +jetstream: enabled +`, operatorJWT, sysApk, sysApk, sysAccountJWT, apk, accountJWT) + if err := os.WriteFile(path.Join(dir, "resolver.conf"), + []byte(resolver), 0644); err != nil { + log.Fatal(err) + } + + // store the creds + credsPath := path.Join(dir, "u.creds") + if err := os.WriteFile(credsPath, creds, 0644); err != nil { + log.Fatal(err) + } +} + +*/