Skip to content

Commit 269e572

Browse files
authored
Merge branch 'AzureAD:master' into master
2 parents 1f3b0ba + 12f21fb commit 269e572

File tree

88 files changed

+5414
-659
lines changed

Some content is hidden

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

88 files changed

+5414
-659
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/InMemoryGroupProvider.cs

Lines changed: 39 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ namespace Microsoft.SCIM.WebHostSample.Provider
55
using System;
66
using System.Collections.Generic;
77
using System.Linq;
8+
using System.Linq.Expressions;
89
using System.Net;
910
using System.Threading.Tasks;
1011
using System.Web.Http;
1112
using Microsoft.SCIM;
12-
using Microsoft.SCIM.WebHostSample.Resources;
1313

1414
public class InMemoryGroupProvider : ProviderBase
1515
{
@@ -44,6 +44,10 @@ public override Task<Resource> CreateAsync(Resource resource, string correlation
4444
{
4545
throw new HttpResponseException(HttpStatusCode.Conflict);
4646
}
47+
//Update Metadata
48+
DateTime created = DateTime.UtcNow;
49+
group.Metadata.Created = created;
50+
group.Metadata.LastModified = created;
4751

4852
string resourceIdentifier = Guid.NewGuid().ToString();
4953
resource.Identifier = resourceIdentifier;
@@ -83,83 +87,61 @@ public override Task<Resource[]> QueryAsync(IQueryParameters parameters, string
8387

8488
if (null == parameters.AlternateFilters)
8589
{
86-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidParameters);
90+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidParameters);
8791
}
8892

8993
if (string.IsNullOrWhiteSpace(parameters.SchemaIdentifier))
9094
{
91-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidParameters);
95+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidParameters);
9296
}
9397

94-
Resource[] results;
98+
IEnumerable<Resource> results;
9599
IFilter queryFilter = parameters.AlternateFilters.SingleOrDefault();
96-
IEnumerable<Core2Group> buffer = Enumerable.Empty<Core2Group>();
100+
101+
var predicate = PredicateBuilder.False<Core2Group>();
102+
Expression<Func<Core2Group, bool>> predicateAnd;
103+
predicateAnd = PredicateBuilder.True<Core2Group>();
104+
97105
if (queryFilter == null)
98106
{
99-
buffer = this.storage.Groups.Values;
107+
results = this.storage.Groups.Values.Select(
108+
(Core2Group user) => user as Resource);
100109
}
101110
else
102111
{
103112
if (string.IsNullOrWhiteSpace(queryFilter.AttributePath))
104113
{
105-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidParameters);
114+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidParameters);
106115
}
107116

108117
if (string.IsNullOrWhiteSpace(queryFilter.ComparisonValue))
109118
{
110-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidParameters);
119+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidParameters);
111120
}
112121

113122
if (queryFilter.FilterOperator != ComparisonOperator.Equals)
114123
{
115-
throw new NotSupportedException(SampleServiceResources.UnsupportedComparisonOperator);
124+
throw new NotSupportedException(string.Format(SystemForCrossDomainIdentityManagementServiceResources.ExceptionFilterOperatorNotSupportedTemplate, queryFilter.FilterOperator));
116125
}
117126

127+
118128
if (queryFilter.AttributePath.Equals(AttributeNames.DisplayName))
119129
{
120-
buffer =
121-
this.storage.Groups.Values
122-
.Where(
123-
(Core2Group item) =>
124-
string.Equals(
125-
item.DisplayName,
126-
parameters.AlternateFilters.Single().ComparisonValue,
127-
StringComparison.OrdinalIgnoreCase));
130+
131+
string displayName = queryFilter.ComparisonValue;
132+
predicateAnd = predicateAnd.And(p => string.Equals(p.DisplayName, displayName, StringComparison.OrdinalIgnoreCase));
133+
128134
}
129135
else
130136
{
131-
throw new NotSupportedException(SampleServiceResources.UnsupportedFilterAttributeGroup);
137+
throw new NotSupportedException(string.Format(SystemForCrossDomainIdentityManagementServiceResources.ExceptionFilterAttributePathNotSupportedTemplate, queryFilter.AttributePath));
132138
}
133139
}
140+
141+
predicate = predicate.Or(predicateAnd);
142+
results = this.storage.Groups.Values.Where(predicate.Compile());
134143

135-
results =
136-
buffer
137-
.Select((Core2Group item) =>
138-
{
139-
Core2Group bufferItem =
140-
new Core2Group
141-
{
142-
DisplayName = item.DisplayName,
143-
ExternalIdentifier = item.ExternalIdentifier,
144-
Identifier = item.Identifier,
145-
Members = item.Members,
146-
Metadata = item.Metadata
147-
};
148-
149-
if (parameters?.ExcludedAttributePaths?.Any(
150-
(string excludedAttributes) =>
151-
excludedAttributes.Equals(AttributeNames.Members, StringComparison.OrdinalIgnoreCase))
152-
== true)
153-
{
154-
bufferItem.Members = null;
155-
}
156-
157-
return bufferItem;
158-
})
159-
.Select((Core2Group item) => item as Resource)
160-
.ToArray();
161-
162-
return Task.FromResult(results);
144+
return Task.FromResult(results.ToArray());
163145
}
164146

165147
public override Task<Resource> ReplaceAsync(Resource resource, string correlationIdentifier)
@@ -176,10 +158,10 @@ public override Task<Resource> ReplaceAsync(Resource resource, string correlatio
176158
throw new HttpResponseException(HttpStatusCode.BadRequest);
177159
}
178160

179-
IEnumerable<Core2Group> exisitingGroups = this.storage.Groups.Values;
161+
Core2Group exisitingGroups = resource as Core2Group;
180162
if
181163
(
182-
exisitingGroups.Any(
164+
this.storage.Groups.Values.Any(
183165
(Core2Group exisitingUser) =>
184166
string.Equals(exisitingUser.DisplayName, group.DisplayName, StringComparison.Ordinal) &&
185167
!string.Equals(exisitingUser.Identifier, group.Identifier, StringComparison.OrdinalIgnoreCase))
@@ -193,6 +175,10 @@ public override Task<Resource> ReplaceAsync(Resource resource, string correlatio
193175
throw new HttpResponseException(HttpStatusCode.NotFound);
194176
}
195177

178+
// Update metadata
179+
group.Metadata.Created = exisitingGroups.Metadata.Created;
180+
group.Metadata.LastModified = DateTime.UtcNow;
181+
196182
this.storage.Groups[group.Identifier] = group;
197183
Resource result = group as Resource;
198184
return Task.FromResult(result);
@@ -238,17 +224,17 @@ public override Task UpdateAsync(IPatch patch, string correlationIdentifier)
238224

239225
if (null == patch.ResourceIdentifier)
240226
{
241-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidPatch);
227+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidOperation);
242228
}
243229

244230
if (string.IsNullOrWhiteSpace(patch.ResourceIdentifier.Identifier))
245231
{
246-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidPatch);
232+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidOperation);
247233
}
248234

249235
if (null == patch.PatchRequest)
250236
{
251-
throw new ArgumentException(SampleServiceResources.ExceptionInvalidPatch);
237+
throw new ArgumentException(SystemForCrossDomainIdentityManagementServiceResources.ExceptionInvalidOperation);
252238
}
253239

254240
PatchRequest2 patchRequest =
@@ -263,6 +249,8 @@ public override Task UpdateAsync(IPatch patch, string correlationIdentifier)
263249
if (this.storage.Groups.TryGetValue(patch.ResourceIdentifier.Identifier, out Core2Group group))
264250
{
265251
group.Apply(patchRequest);
252+
// Update metadata
253+
group.Metadata.LastModified = DateTime.UtcNow;
266254
}
267255
else
268256
{

Microsoft.SCIM.WebHostSample/Provider/InMemoryProvider.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,45 @@
33
namespace Microsoft.SCIM.WebHostSample.Provider
44
{
55
using System;
6+
using System.Collections.Generic;
67
using System.Threading.Tasks;
78
using Microsoft.SCIM;
9+
using Microsoft.SCIM.WebHostSample.Resources;
810

911
public class InMemoryProvider : ProviderBase
1012
{
1113
private readonly ProviderBase groupProvider;
1214
private readonly ProviderBase userProvider;
1315

16+
private static readonly Lazy<IReadOnlyCollection<TypeScheme>> TypeSchema =
17+
new Lazy<IReadOnlyCollection<TypeScheme>>(
18+
() =>
19+
new TypeScheme[]
20+
{
21+
SampleTypeScheme.UserTypeScheme,
22+
SampleTypeScheme.GroupTypeScheme,
23+
SampleTypeScheme.EnterpriseUserTypeScheme,
24+
SampleTypeScheme.ResourceTypesTypeScheme,
25+
SampleTypeScheme.SchemaTypeScheme,
26+
SampleTypeScheme.ServiceProviderConfigTypeScheme
27+
});
28+
29+
private static readonly Lazy<IReadOnlyCollection<Core2ResourceType>> Types =
30+
new Lazy<IReadOnlyCollection<Core2ResourceType>>(
31+
() =>
32+
new Core2ResourceType[] { SampleResourceTypes.UserResourceType, SampleResourceTypes.GroupResourceType } );
33+
34+
1435
public InMemoryProvider()
1536
{
1637
this.groupProvider = new InMemoryGroupProvider();
1738
this.userProvider = new InMemoryUserProvider();
1839
}
1940

41+
public override IReadOnlyCollection<Core2ResourceType> ResourceTypes => InMemoryProvider.Types.Value;
42+
43+
public override IReadOnlyCollection<TypeScheme> Schema => InMemoryProvider.TypeSchema.Value;
44+
2045
public override Task<Resource> CreateAsync(Resource resource, string correlationIdentifier)
2146
{
2247
if (resource is Core2EnterpriseUser)

Microsoft.SCIM.WebHostSample/Provider/InMemoryStorage.cs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace Microsoft.SCIM.WebHostSample.Provider
44
{
55
using System;
66
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Linq.Expressions;
79
using Microsoft.SCIM;
810

911
public class InMemoryStorage
@@ -22,12 +24,45 @@ private InMemoryStorage()
2224
() =>
2325
new InMemoryStorage());
2426

25-
public static InMemoryStorage Instance
27+
public static InMemoryStorage Instance => InMemoryStorage.InstanceValue.Value;
28+
}
29+
30+
/// <summary>
31+
/// Enables the efficient, dynamic composition of query predicates.
32+
/// Source: C# 9.0 in a Nutshell http://www.albahari.com/nutshell/predicatebuilder.aspx
33+
/// </summary>
34+
public static class PredicateBuilder
35+
{
36+
/// <summary>
37+
/// Creates a predicate that evaluates to true.
38+
/// </summary>
39+
public static Expression<Func<T, bool>> True<T>() { return f => true; }
40+
/// <summary>
41+
/// Creates a predicate that evaluates to false.
42+
/// </summary>
43+
public static Expression<Func<T, bool>> False<T>() { return f => false; }
44+
45+
/// <summary>
46+
/// Combines the first predicate with the second using the logical "or".
47+
/// </summary>
48+
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
49+
Expression<Func<T, bool>> expr2)
2650
{
27-
get
28-
{
29-
return InMemoryStorage.InstanceValue.Value;
30-
}
51+
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
52+
return Expression.Lambda<Func<T, bool>>
53+
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
54+
}
55+
56+
/// <summary>
57+
/// Combines the first predicate with the second using the logical "and".
58+
/// </summary>
59+
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
60+
Expression<Func<T, bool>> expr2)
61+
{
62+
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
63+
return Expression.Lambda<Func<T, bool>>
64+
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
3165
}
3266
}
67+
3368
}

0 commit comments

Comments
 (0)