Skip to content

Commit 471496c

Browse files
authored
[PM-28045] - Org Key Validation (#7384)
* Requiring keys on create request models. * Added tests.
1 parent dcc685d commit 471496c

5 files changed

Lines changed: 174 additions & 3 deletions

File tree

src/Api/AdminConsole/Models/Request/Organizations/OrganizationCreateRequestModel.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class OrganizationCreateRequestModel : IValidatableObject
3333
[Required]
3434
public string Key { get; set; }
3535

36+
[Required]
3637
public OrganizationKeysRequestModel Keys { get; set; }
3738
public PaymentMethodType? PaymentMethodType { get; set; }
3839
public string PaymentToken { get; set; }
@@ -117,7 +118,7 @@ public virtual OrganizationSignup ToOrganizationSignup(User user)
117118
InitiationPath = InitiationPath,
118119
SkipTrial = SkipTrial,
119120
Coupons = Coupons,
120-
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
121+
Keys = Keys.ToPublicKeyEncryptionKeyPairData()
121122
};
122123

123124
return orgSignup;

src/Api/AdminConsole/Models/Request/Organizations/OrganizationNoPaymentCreateRequest.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class OrganizationNoPaymentCreateRequest
3232
[Required]
3333
public string Key { get; set; }
3434

35+
[Required]
3536
public OrganizationKeysRequestModel Keys { get; set; }
3637
public PaymentMethodType? PaymentMethodType { get; set; }
3738
public string PaymentToken { get; set; }
@@ -110,7 +111,7 @@ public virtual OrganizationSignup ToOrganizationSignup(User user)
110111
BillingAddressCountry = BillingAddressCountry,
111112
},
112113
InitiationPath = InitiationPath,
113-
Keys = Keys?.ToPublicKeyEncryptionKeyPairData()
114+
Keys = Keys.ToPublicKeyEncryptionKeyPairData()
114115
};
115116

116117
return orgSignup;

test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationsControllerPerformanceTests.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,12 @@ public async Task CreateOrganization_WithoutPayment()
155155
AdditionalServiceAccounts = 2,
156156
MaxAutoscaleSeats = 100,
157157
PremiumAccessAddon = false,
158-
CollectionName = "2.AOs41Hd8OQiCPXjyJKCiDA==|O6OHgt2U2hJGBSNGnimJmg==|iD33s8B69C8JhYYhSa4V1tArjvLr8eEaGqOV7BRo5Jk="
158+
CollectionName = "2.AOs41Hd8OQiCPXjyJKCiDA==|O6OHgt2U2hJGBSNGnimJmg==|iD33s8B69C8JhYYhSa4V1tArjvLr8eEaGqOV7BRo5Jk=",
159+
Keys = new OrganizationKeysRequestModel
160+
{
161+
PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0OaLBJiGh5GJmX8hV/a",
162+
EncryptedPrivateKey = "2.AOs41Hd8OQiCPXjyJKCiDA==|O6OHgt2U2hJGBSNGnimJmg==|iD33s8B69C8JhYYhSa4V1tArjvLr8eEaGqOV7BRo5Jk="
163+
}
159164
};
160165

161166
var requestContent = new StringContent(JsonSerializer.Serialize(createRequest), Encoding.UTF8, "application/json");
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using Bit.Api.AdminConsole.Models.Request.Organizations;
3+
using Xunit;
4+
5+
namespace Bit.Api.Test.AdminConsole.Models.Request.Organizations;
6+
7+
public class OrganizationCreateRequestModelTests
8+
{
9+
[Fact]
10+
public void Validate_KeysMissing_FailsValidation()
11+
{
12+
var model = new OrganizationCreateRequestModel
13+
{
14+
Name = "Test Org",
15+
BillingEmail = "test@example.com",
16+
Key = "test-key",
17+
UseSecretsManager = false,
18+
Keys = null
19+
};
20+
21+
var results = ValidateModel(model);
22+
23+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationCreateRequestModel.Keys)));
24+
}
25+
26+
[Fact]
27+
public void Validate_KeysPresent_PassesKeysValidation()
28+
{
29+
var model = new OrganizationCreateRequestModel
30+
{
31+
Name = "Test Org",
32+
BillingEmail = "test@example.com",
33+
Key = "test-key",
34+
UseSecretsManager = false,
35+
Keys = new OrganizationKeysRequestModel
36+
{
37+
PublicKey = "test-public-key",
38+
EncryptedPrivateKey = "test-encrypted-private-key"
39+
}
40+
};
41+
42+
var results = ValidateModel(model);
43+
44+
Assert.DoesNotContain(results, r => r.MemberNames.Contains(nameof(OrganizationCreateRequestModel.Keys)));
45+
}
46+
47+
[Fact]
48+
public void Validate_KeysMissingPublicKey_FailsValidation()
49+
{
50+
var keys = new OrganizationKeysRequestModel
51+
{
52+
PublicKey = null,
53+
EncryptedPrivateKey = "test-encrypted-private-key"
54+
};
55+
56+
var results = ValidateModel(keys);
57+
58+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationKeysRequestModel.PublicKey)));
59+
}
60+
61+
[Fact]
62+
public void Validate_KeysMissingEncryptedPrivateKey_FailsValidation()
63+
{
64+
var keys = new OrganizationKeysRequestModel
65+
{
66+
PublicKey = "test-public-key",
67+
EncryptedPrivateKey = null
68+
};
69+
70+
var results = ValidateModel(keys);
71+
72+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationKeysRequestModel.EncryptedPrivateKey)));
73+
}
74+
75+
private static List<ValidationResult> ValidateModel(object model)
76+
{
77+
var context = new ValidationContext(model);
78+
var results = new List<ValidationResult>();
79+
Validator.TryValidateObject(model, context, results, validateAllProperties: true);
80+
return results;
81+
}
82+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using Bit.Api.AdminConsole.Models.Request.Organizations;
3+
using Xunit;
4+
5+
namespace Bit.Api.Test.AdminConsole.Models.Request.Organizations;
6+
7+
public class OrganizationNoPaymentCreateRequestTests
8+
{
9+
[Fact]
10+
public void Validate_KeysMissing_FailsValidation()
11+
{
12+
var model = new OrganizationNoPaymentCreateRequest
13+
{
14+
Name = "Test Org",
15+
BillingEmail = "test@example.com",
16+
Key = "test-key",
17+
UseSecretsManager = false,
18+
Keys = null
19+
};
20+
21+
var results = ValidateModel(model);
22+
23+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationNoPaymentCreateRequest.Keys)));
24+
}
25+
26+
[Fact]
27+
public void Validate_KeysPresent_PassesKeysValidation()
28+
{
29+
var model = new OrganizationNoPaymentCreateRequest
30+
{
31+
Name = "Test Org",
32+
BillingEmail = "test@example.com",
33+
Key = "test-key",
34+
UseSecretsManager = false,
35+
Keys = new OrganizationKeysRequestModel
36+
{
37+
PublicKey = "test-public-key",
38+
EncryptedPrivateKey = "test-encrypted-private-key"
39+
}
40+
};
41+
42+
var results = ValidateModel(model);
43+
44+
Assert.DoesNotContain(results, r => r.MemberNames.Contains(nameof(OrganizationNoPaymentCreateRequest.Keys)));
45+
}
46+
47+
[Fact]
48+
public void Validate_KeysMissingPublicKey_FailsValidation()
49+
{
50+
var keys = new OrganizationKeysRequestModel
51+
{
52+
PublicKey = null,
53+
EncryptedPrivateKey = "test-encrypted-private-key"
54+
};
55+
56+
var results = ValidateModel(keys);
57+
58+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationKeysRequestModel.PublicKey)));
59+
}
60+
61+
[Fact]
62+
public void Validate_KeysMissingEncryptedPrivateKey_FailsValidation()
63+
{
64+
var keys = new OrganizationKeysRequestModel
65+
{
66+
PublicKey = "test-public-key",
67+
EncryptedPrivateKey = null
68+
};
69+
70+
var results = ValidateModel(keys);
71+
72+
Assert.Contains(results, r => r.MemberNames.Contains(nameof(OrganizationKeysRequestModel.EncryptedPrivateKey)));
73+
}
74+
75+
private static List<ValidationResult> ValidateModel(object model)
76+
{
77+
var context = new ValidationContext(model);
78+
var results = new List<ValidationResult>();
79+
Validator.TryValidateObject(model, context, results, validateAllProperties: true);
80+
return results;
81+
}
82+
}

0 commit comments

Comments
 (0)