Skip to content

Commit d6a5d06

Browse files
committed
Add test cases
Signed-off-by: Victor Chang <vicchang@nvidia.com>
1 parent afaca88 commit d6a5d06

8 files changed

+178
-25
lines changed

src/Authentication/Configurations/AuthenticationOptions.cs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ public bool BypassAuth(ILogger logger)
4444
{
4545
throw new InvalidOperationException("openId configuration is invalid.");
4646
}
47-
if (OpenId.Claims is null || OpenId.Claims.UserClaims!.IsNullOrEmpty() || OpenId.Claims.AdminClaims!.IsNullOrEmpty())
48-
{
49-
throw new InvalidOperationException("No claimMappings defined for OpenId.");
50-
}
5147
if (string.IsNullOrWhiteSpace(OpenId.ClientId))
5248
{
5349
throw new InvalidOperationException("No clientId defined for OpenId.");
@@ -60,8 +56,44 @@ public bool BypassAuth(ILogger logger)
6056
{
6157
throw new InvalidOperationException("No realm defined for OpenId.");
6258
}
59+
if (OpenId.Claims is null || OpenId.Claims.UserClaims!.IsNullOrEmpty() || OpenId.Claims.AdminClaims!.IsNullOrEmpty())
60+
{
61+
throw new InvalidOperationException("No claimMappings defined for OpenId.");
62+
}
63+
64+
ValidateClaims(OpenId.Claims.UserClaims!, true);
65+
ValidateClaims(OpenId.Claims.AdminClaims!, false);
6366

6467
return false;
6568
}
69+
70+
private void ValidateClaims(List<ClaimMapping> claims, bool validateEndpoints)
71+
{
72+
foreach (var claim in claims)
73+
{
74+
if (string.IsNullOrWhiteSpace(claim.ClaimType))
75+
{
76+
throw new InvalidOperationException("Value for claimType is invalid.");
77+
}
78+
79+
if (claim.ClaimValues.IsNullOrEmpty())
80+
{
81+
throw new InvalidOperationException("Value for claimType is invalid.");
82+
}
83+
84+
foreach (var claimValue in claim.ClaimValues)
85+
{
86+
if (string.IsNullOrWhiteSpace(claimValue))
87+
{
88+
throw new InvalidOperationException($"Invalid claimValue for {claim.ClaimType}.");
89+
}
90+
}
91+
92+
if (validateEndpoints && claim.Endpoints.IsNullOrEmpty())
93+
{
94+
throw new InvalidOperationException("Value for claimType is invalid.");
95+
}
96+
}
97+
}
6698
}
6799
}

src/Authentication/Configurations/OpenIdOptions.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
using System.Security.Claims;
1718
using Microsoft.Extensions.Configuration;
1819

1920
namespace Monai.Deploy.Security.Authentication.Configurations
@@ -36,6 +37,9 @@ public class OpenIdOptions
3637
public IList<string>? Audiences { get; set; }
3738

3839
[ConfigurationKeyName("roleClaimType")]
39-
public string RoleClaimType { get; set; } = "roles";
40+
public string RoleClaimType { get; set; } = ClaimTypes.Role;
41+
42+
[ConfigurationKeyName("clearDefaultRoleMappigns")]
43+
public bool ClearDefaultRoleMappigns { get; set; } = true;
4044
}
4145
}

src/Authentication/Extensions/MonaiAuthenticationExtensions.cs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
using System.IdentityModel.Tokens.Jwt;
1718
using System.Text;
1819
using Microsoft.AspNetCore.Authentication;
1920
using Microsoft.AspNetCore.Authentication.JwtBearer;
@@ -48,29 +49,36 @@ public static IServiceCollection AddMonaiAuthentication(
4849
return services;
4950
}
5051

51-
services.AddAuthentication(options =>
52+
if (configurations.Value.OpenId?.ClearDefaultRoleMappigns ?? false)
5253
{
53-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
54-
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
55-
})
56-
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, AuthKeys.OpenId, options =>
57-
{
58-
options.Authority = configurations.Value.OpenId!.Realm;
59-
options.Audience = configurations.Value.OpenId!.Realm;
60-
options.RequireHttpsMetadata = false;
54+
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
55+
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("roles");
56+
}
6157

62-
options.TokenValidationParameters = new TokenValidationParameters
58+
services
59+
.AddAuthentication(options =>
6360
{
64-
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configurations.Value.OpenId!.RealmKey!)),
65-
RoleClaimType = configurations.Value.OpenId.RoleClaimType,
66-
ValidIssuer = configurations.Value.OpenId.Realm,
67-
ValidAudiences = configurations.Value.OpenId.Audiences,
68-
ValidateIssuerSigningKey = true,
69-
ValidateIssuer = true,
70-
ValidateLifetime = true,
71-
ValidateAudience = true,
72-
};
73-
});
61+
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
62+
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
63+
})
64+
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, AuthKeys.OpenId, options =>
65+
{
66+
options.Authority = configurations.Value.OpenId!.Realm;
67+
options.Audience = configurations.Value.OpenId!.Realm;
68+
options.RequireHttpsMetadata = false;
69+
70+
options.TokenValidationParameters = new TokenValidationParameters
71+
{
72+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configurations.Value.OpenId!.RealmKey!)),
73+
RoleClaimType = configurations.Value.OpenId.RoleClaimType,
74+
ValidIssuer = configurations.Value.OpenId.Realm,
75+
ValidAudiences = configurations.Value.OpenId.Audiences,
76+
ValidateIssuerSigningKey = true,
77+
ValidateIssuer = true,
78+
ValidateLifetime = true,
79+
ValidateAudience = true,
80+
};
81+
});
7482

7583
services.AddAuthorization();
7684
return services;

src/Authentication/Tests/EndpointAuthorizationMiddlewareTest.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ public partial class EndpointAuthorizationMiddlewareTest
3232
[InlineData("test.auth-noclientid.json")]
3333
[InlineData("test.auth-norealm.json")]
3434
[InlineData("test.auth-norealmkey.json")]
35+
[InlineData("test.auth-noclaimtype.json")]
36+
[InlineData("test.auth-noclaimvalues.json")]
37+
[InlineData("test.auth-whitespaceclaimvalues.json")]
38+
[InlineData("test.auth-noendpoints.json")]
3539
public async Task GivenConfigurationFilesIsBad_ExpectExceptionToBeThrown(string configFile)
3640
{
3741
await Assert.ThrowsAsync<InvalidOperationException>(async () =>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"MonaiDeployAuthentication": {
3+
"bypassAuthentication": false,
4+
"openId": {
5+
"realm": "TEST-REALM",
6+
"realmKey": "l9ZRlbMQBt9k1klUUrlWFuke8WbqnEde",
7+
"audiences": [ "monai-app" ],
8+
"roleClaimType": "roles",
9+
"clientId": "monai-app-test",
10+
"claimMappings": {
11+
"userClaims": [
12+
{
13+
"claimType": "",
14+
"claimValues": [ "role-with-test" ],
15+
"endpoints": [ "test" ]
16+
}
17+
],
18+
"adminClaims": [
19+
{
20+
"claimType": "",
21+
"claimValues": [ "monai-role-admin" ]
22+
}
23+
]
24+
}
25+
}
26+
}
27+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"MonaiDeployAuthentication": {
3+
"bypassAuthentication": false,
4+
"openId": {
5+
"realm": "TEST-REALM",
6+
"realmKey": "l9ZRlbMQBt9k1klUUrlWFuke8WbqnEde",
7+
"audiences": [ "monai-app" ],
8+
"roleClaimType": "roles",
9+
"clientId": "monai-app-test",
10+
"claimMappings": {
11+
"userClaims": [
12+
{
13+
"claimType": "user_roles",
14+
"endpoints": [ "test" ]
15+
}
16+
],
17+
"adminClaims": [
18+
{
19+
"claimType": "user_roles",
20+
}
21+
]
22+
}
23+
}
24+
}
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"MonaiDeployAuthentication": {
3+
"bypassAuthentication": false,
4+
"openId": {
5+
"realm": "TEST-REALM",
6+
"realmKey": "l9ZRlbMQBt9k1klUUrlWFuke8WbqnEde",
7+
"audiences": [ "monai-app" ],
8+
"roleClaimType": "roles",
9+
"clientId": "monai-app-test",
10+
"claimMappings": {
11+
"userClaims": [
12+
{
13+
"claimType": "user_roles",
14+
"claimValues": [ "role-with-test" ]
15+
}
16+
],
17+
"adminClaims": [
18+
{
19+
"claimType": "user_roles",
20+
"claimValues": [ "monai-role-admin" ]
21+
}
22+
]
23+
}
24+
}
25+
}
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"MonaiDeployAuthentication": {
3+
"bypassAuthentication": false,
4+
"openId": {
5+
"realm": "TEST-REALM",
6+
"realmKey": "l9ZRlbMQBt9k1klUUrlWFuke8WbqnEde",
7+
"audiences": [ "monai-app" ],
8+
"roleClaimType": "roles",
9+
"clientId": "monai-app-test",
10+
"claimMappings": {
11+
"userClaims": [
12+
{
13+
"claimType": "user_roles",
14+
"claimValues": [ " " ],
15+
"endpoints": [ "test" ]
16+
}
17+
],
18+
"adminClaims": [
19+
{
20+
"claimType": "user_roles",
21+
"claimValues": [ " " ]
22+
}
23+
]
24+
}
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)