Skip to content

Commit 3409911

Browse files
charitymaraniRyanmeakinsRyanECharity Marani
authored
Endpoint fixes (#30) (#53)
* Adds returning of sample resource types from the endpoint * Adds sample schema types support * fix: Make schema discovery response SCIM compliant - Fix type property's value in atttributes schema to be camelCase - Add subAttributes to complex types - Add schemas attribute to Schema resource - Remove all unused imports - Put all using statements inside namespace - Fix typos in the code - Use expression body where necessary - Add Authentication Co-authored-by: RyanE <[email protected]> Co-authored-by: Charity Marani <[email protected]> Co-authored-by: Ryanmeakins <[email protected]> Co-authored-by: RyanE <[email protected]> Co-authored-by: Charity Marani <[email protected]>
1 parent b2b13fa commit 3409911

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2413
-160
lines changed

Microsoft.SCIM.WebHostSample/Controllers/TokenController.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,18 @@ public TokenController(IConfiguration Configuration)
2727

2828
private string GenerateJSONWebToken()
2929
{
30-
// Create token key
3130
SymmetricSecurityKey securityKey =
3231
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.configuration["Token:IssuerSigningKey"]));
3332
SigningCredentials credentials =
3433
new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
3534

36-
// Set token expiration
3735
DateTime startTime = DateTime.UtcNow;
3836
DateTime expiryTime;
3937
if (double.TryParse(this.configuration["Token:TokenLifetimeInMins"], out double tokenExpiration))
4038
expiryTime = startTime.AddMinutes(tokenExpiration);
4139
else
4240
expiryTime = startTime.AddMinutes(defaultTokenExpirationTimeInMins);
4341

44-
// Generate the token
4542
JwtSecurityToken token =
4643
new JwtSecurityToken(
4744
this.configuration["Token:TokenIssuer"],

Microsoft.SCIM.WebHostSample/Provider/InMemoryStorage.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,5 @@ private InMemoryStorage()
2323
new InMemoryStorage());
2424

2525
public static InMemoryStorage Instance => InMemoryStorage.InstanceValue.Value;
26-
2726
}
2827
}

Microsoft.SCIM.WebHostSample/Startup.cs

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ namespace Microsoft.SCIM.WebHostSample
66
{
77
using System.Text;
88
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Authentication;
910
using Microsoft.AspNetCore.Authentication.JwtBearer;
1011
using Microsoft.AspNetCore.Builder;
1112
using Microsoft.AspNetCore.Hosting;
13+
using Microsoft.AspNetCore.Mvc;
1214
using Microsoft.AspNetCore.Routing;
1315
using Microsoft.Extensions.Configuration;
1416
using Microsoft.Extensions.DependencyInjection;
@@ -38,67 +40,49 @@ public Startup(IWebHostEnvironment env, IConfiguration configuration)
3840
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
3941
public void ConfigureServices(IServiceCollection services)
4042
{
41-
if (this.environment.IsDevelopment())
43+
void ConfigureMvcNewtonsoftJsonOptions(MvcNewtonsoftJsonOptions options) => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
44+
45+
void ConfigureAuthenticationOptions(AuthenticationOptions options)
4246
{
43-
// Development environment code
44-
// Validation for bearer token for authorization used during testing.
45-
// NOTE: It's not recommended to use this code in production, it is not meant to replace proper OAuth authentication.
46-
// This option is primarily available for testing purposes.
47-
services.AddAuthentication(options =>
48-
{
49-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
50-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
51-
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
52-
})
53-
.AddJwtBearer(options =>
54-
{
55-
options.TokenValidationParameters =
56-
new TokenValidationParameters
57-
{
58-
ValidateIssuer = false,
59-
ValidateAudience = false,
60-
ValidateLifetime = false,
61-
ValidateIssuerSigningKey = false,
62-
ValidIssuer = this.configuration["Token:TokenIssuer"],
63-
ValidAudience = this.configuration["Token:TokenAudience"],
64-
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.configuration["Token:IssuerSigningKey"]))
65-
};
66-
});
47+
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
48+
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
6749
}
68-
else
50+
51+
void ConfigureJwtBearerOptons( JwtBearerOptions options)
6952
{
70-
// Leave the optional Secret Token field blank
71-
// Azure AD includes an OAuth bearer token issued from Azure AD with each request
72-
// The following code validates the Azure AD-issued token
73-
// NOTE: It's not recommended to leave this field blank and rely on a token generated by Azure AD.
74-
// This option is primarily available for testing purposes.
75-
services.AddAuthentication(options =>
53+
if (this.environment.IsDevelopment())
7654
{
77-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
78-
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
79-
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
80-
})
81-
.AddJwtBearer(options =>
55+
options.TokenValidationParameters =
56+
new TokenValidationParameters
57+
{
58+
ValidateIssuer = false,
59+
ValidateAudience = false,
60+
ValidateLifetime = false,
61+
ValidateIssuerSigningKey = false,
62+
ValidIssuer = this.configuration["Token:TokenIssuer"],
63+
ValidAudience = this.configuration["Token:TokenAudience"],
64+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.configuration["Token:IssuerSigningKey"]))
65+
};
66+
}
67+
else
8268
{
8369
options.Authority = this.configuration["Token:TokenIssuer"];
8470
options.Audience = this.configuration["Token:TokenAudience"];
8571
options.Events = new JwtBearerEvents
8672
{
8773
OnTokenValidated = context =>
8874
{
89-
// NOTE: You can optionally take action when the OAuth 2.0 bearer token was validated.
90-
9175
return Task.CompletedTask;
9276
},
9377
OnAuthenticationFailed = AuthenticationFailed
9478
};
95-
});
79+
}
80+
9681
}
9782

98-
services.AddControllers().AddNewtonsoftJson(options =>
99-
{
100-
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
101-
});
83+
services.AddAuthentication(ConfigureAuthenticationOptions).AddJwtBearer(ConfigureJwtBearerOptons);
84+
services.AddControllers().AddNewtonsoftJson(ConfigureMvcNewtonsoftJsonOptions);
85+
10286
services.AddSingleton(typeof(IProvider), this.ProviderBehavior);
10387
services.AddSingleton(typeof(IMonitor), this.MonitoringBehavior);
10488
}
@@ -112,7 +96,6 @@ public void Configure(IApplicationBuilder app)
11296
}
11397

11498
app.UseHsts();
115-
11699
app.UseRouting();
117100
app.UseHttpsRedirection();
118101
app.UseAuthentication();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
5+
namespace Microsoft.SCIM
6+
{
7+
using System;
8+
using System.Net.Http;
9+
using System.Runtime.Serialization;
10+
11+
[DataContract]
12+
public abstract class BulkOperation
13+
{
14+
private HttpMethod method;
15+
private string methodName;
16+
17+
protected BulkOperation()
18+
{
19+
this.Identifier = Guid.NewGuid().ToString();
20+
}
21+
22+
protected BulkOperation(string identifier)
23+
{
24+
this.Identifier = identifier;
25+
}
26+
27+
[DataMember(Name = ProtocolAttributeNames.BulkOperationIdentifier, Order = 1)]
28+
public string Identifier
29+
{
30+
get;
31+
private set;
32+
}
33+
34+
public HttpMethod Method
35+
{
36+
get => this.method;
37+
38+
set
39+
{
40+
this.method = value;
41+
if (value != null)
42+
{
43+
this.methodName = value.ToString();
44+
}
45+
}
46+
}
47+
48+
[DataMember(Name = ProtocolAttributeNames.Method, Order = 0)]
49+
#pragma warning disable IDE0051 // Remove unused private members
50+
private string MethodName
51+
#pragma warning restore IDE0051 // Remove unused private members
52+
{
53+
get => this.methodName;
54+
55+
set
56+
{
57+
this.method = new HttpMethod(value);
58+
this.methodName = value;
59+
}
60+
}
61+
}
62+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
5+
namespace Microsoft.SCIM
6+
{
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Runtime.Serialization;
11+
12+
[DataContract]
13+
public abstract class BulkOperations<TOperation> : Schematized where TOperation : BulkOperation
14+
{
15+
[DataMember(Name = ProtocolAttributeNames.Operations, Order = 2)]
16+
private List<TOperation> operations;
17+
private IReadOnlyCollection<TOperation> operationsWrapper;
18+
19+
private object thisLock;
20+
21+
protected BulkOperations(string schemaIdentifier)
22+
{
23+
if (string.IsNullOrWhiteSpace(schemaIdentifier))
24+
{
25+
throw new ArgumentNullException(nameof(schemaIdentifier));
26+
}
27+
28+
this.AddSchema(schemaIdentifier);
29+
this.OnInitialization();
30+
this.OnInitialized();
31+
}
32+
33+
public IReadOnlyCollection<TOperation> Operations => this.operationsWrapper;
34+
35+
public void AddOperation(TOperation operation)
36+
{
37+
if (null == operation)
38+
{
39+
throw new ArgumentNullException(nameof(operation));
40+
}
41+
42+
if (string.IsNullOrWhiteSpace(operation.Identifier))
43+
{
44+
throw new ArgumentException(
45+
SystemForCrossDomainIdentityManagementProtocolResources.ExceptionUnidentifiableOperation);
46+
}
47+
48+
bool Contains() => this.operations.Any((BulkOperation item) => string.Equals(item.Identifier, operation.Identifier,
49+
StringComparison.OrdinalIgnoreCase));
50+
51+
if (!Contains())
52+
{
53+
lock (this.thisLock)
54+
{
55+
if (!Contains())
56+
{
57+
this.operations.Add(operation);
58+
}
59+
}
60+
}
61+
}
62+
63+
[OnDeserialized]
64+
private void OnDeserialized(StreamingContext _) => this.OnInitialized();
65+
66+
[OnDeserializing]
67+
private void OnDeserializing(StreamingContext _) => this.OnInitialization();
68+
69+
private void OnInitialization()
70+
{
71+
this.thisLock = new object();
72+
this.operations = new List<TOperation>();
73+
}
74+
75+
private void OnInitialized() => this.operationsWrapper = this.operations.AsReadOnly();
76+
}
77+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
//------------------------------------------------------------
4+
5+
namespace Microsoft.SCIM
6+
{
7+
using System.Runtime.Serialization;
8+
9+
[DataContract]
10+
public sealed class BulkRequest2 : BulkOperations<BulkRequestOperation>
11+
{
12+
public BulkRequest2()
13+
: base(ProtocolSchemaIdentifiers.Version2BulkRequest)
14+
{
15+
}
16+
17+
[DataMember(Name = ProtocolAttributeNames.FailOnErrors, Order = 1)]
18+
public int? FailOnErrors
19+
{
20+
get;
21+
set;
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)