Skip to content

Commit f4c32e4

Browse files
Ticket #319 : Case insensitive
1 parent 62d5d76 commit f4c32e4

8 files changed

Lines changed: 89 additions & 48 deletions

File tree

src/Scim/SimpleIdServer.Scim/Api/BaseApiController.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,11 +454,7 @@ protected async Task<IActionResult> InternalGet(string id)
454454

455455
protected async Task<IActionResult> InternalAdd(RepresentationParameter jobj)
456456
{
457-
if (jobj == null)
458-
{
459-
return this.BuildError(HttpStatusCode.BadRequest, Global.HttpPostNotWellFormatted, SCIMConstants.ErrorSCIMTypes.InvalidSyntax);
460-
}
461-
457+
if (jobj == null) return this.BuildError(HttpStatusCode.BadRequest, Global.HttpPostNotWellFormatted, SCIMConstants.ErrorSCIMTypes.InvalidSyntax);
462458
_logger.LogInformation(Global.AddResource);
463459
try
464460
{

src/Scim/SimpleIdServer.Scim/Commands/Handlers/PatchRepresentationCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ private async Task<PatchRepresentationResult> UpdateRepresentation(SCIMRepresent
6969

7070
private void CheckParameter(PatchRepresentationParameter patchRepresentation)
7171
{
72-
if (patchRepresentation == null)
72+
if (patchRepresentation == null || (patchRepresentation.Operations != null && patchRepresentation.Operations.Any(o => o.Operation == null)))
7373
{
7474
throw new SCIMBadSyntaxException(string.Format(Global.RequestIsNotWellFormatted, "PATCH"));
7575
}

src/Scim/SimpleIdServer.Scim/DTOs/PatchOperationParameter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
// Copyright (c) SimpleIdServer. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3-
43
using Newtonsoft.Json;
5-
using Newtonsoft.Json.Linq;
4+
using SimpleIdServer.Scim.Infrastructure.Converters;
65
using System.Runtime.Serialization;
76

87
namespace SimpleIdServer.Scim.DTOs
98
{
9+
[JsonConverter(typeof(PatchOperationParameterConverter))]
1010
public class PatchOperationParameter
1111
{
1212
/// <summary>
1313
/// Indicates the operation to perform and MAY be one of "add", "remove", or "replace".
1414
/// </summary>
1515
[DataMember(Name = SCIMConstants.PathOperationAttributes.Operation)]
1616
[JsonProperty(SCIMConstants.PathOperationAttributes.Operation)]
17-
public SCIMPatchOperations Operation { get; set; }
17+
public SCIMPatchOperations? Operation { get; set; }
1818
/// <summary>
1919
/// Attribute path describing the target of the operation.
2020
/// </summary>

src/Scim/SimpleIdServer.Scim/DTOs/PatchRepresentationParameter.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) SimpleIdServer. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3-
43
using Newtonsoft.Json;
5-
using System.Collections;
64
using System.Collections.Generic;
75
using System.Runtime.Serialization;
86

src/Scim/SimpleIdServer.Scim/Extensions/JObjectExtensions.cs

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// Copyright (c) SimpleIdServer. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
using Newtonsoft.Json;
34
using Newtonsoft.Json.Linq;
5+
using Newtonsoft.Json.Serialization;
46
using SimpleIdServer.Scim.Domains;
57
using System;
68
using System.Collections.Generic;
9+
using System.Dynamic;
710
using System.Linq;
811

912
namespace SimpleIdServer.Scim.Extensions
@@ -48,7 +51,7 @@ public static bool HasNotEmptyElement(this JObject jObj, string name, string sch
4851

4952
public static IEnumerable<string> GetSchemas(this JObject jObj)
5053
{
51-
return GetArray(jObj, StandardSCIMRepresentationAttributes.Schemas);
54+
return GetArrayIgnoreCase(jObj, StandardSCIMRepresentationAttributes.Schemas);
5255
}
5356

5457
public static bool TryGetInt(this JObject jObj, string name, out int result)
@@ -68,15 +71,29 @@ public static bool TryGetInt(this JObject jObj, string name, out int result)
6871
return false;
6972
}
7073

71-
public static bool TryGetEnum<T>(this JObject jObj, string name, out T result) where T : struct
74+
public static bool TryGetString(this JObject jObj, string name, out string result)
7275
{
73-
result = default(T);
74-
string r;
75-
if (!jObj.TryGetString(name, out r))
76+
result = null;
77+
if (!jObj.ContainsKey(name))
7678
{
7779
return false;
7880
}
7981

82+
result = jObj[name].ToString();
83+
return true;
84+
}
85+
86+
public static string GetStringIgnoreCase(this JObject jObj, string name)
87+
{
88+
if (jObj.TryGetValue(name, StringComparison.InvariantCultureIgnoreCase, out JToken value)) return value.ToString();
89+
return null;
90+
}
91+
92+
public static bool TryGetEnumIgnoreCase<T>(this JObject jObj, string name, out T result) where T : struct
93+
{
94+
result = default(T);
95+
string r = jObj.GetStringIgnoreCase(name);
96+
if (string.IsNullOrWhiteSpace(r)) return false;
8097
var enumName = Enum.GetNames(typeof(T)).FirstOrDefault(n => n.Equals(r, StringComparison.InvariantCultureIgnoreCase));
8198
if (string.IsNullOrWhiteSpace(enumName))
8299
{
@@ -87,42 +104,34 @@ public static bool TryGetEnum<T>(this JObject jObj, string name, out T result) w
87104
return true;
88105
}
89106

90-
public static bool TryGetString(this JObject jObj, string name, out string result)
107+
public static IEnumerable<string> GetArrayIgnoreCase(this JObject jObj, string name)
91108
{
92-
result = null;
93-
if (!jObj.ContainsKey(name))
94-
{
95-
return false;
96-
}
97-
98-
result = jObj[name].ToString();
99-
return true;
109+
JToken value = null;
110+
if (!jObj.TryGetValue(name, StringComparison.InvariantCultureIgnoreCase, out value)) return new string[0];
111+
var jArr = value as JArray;
112+
if (jArr == null) return new string[0];
113+
return jArr.Values<string>().ToList();
100114
}
101115

102-
public static string GetString(this JObject jObj, string name)
116+
public static void RemoveIgnoreCase(this JObject jObj, string name)
103117
{
104-
if (!jObj.ContainsKey(name))
105-
{
106-
return null;
107-
}
108-
109-
return jObj[name].ToString();
118+
JToken value = null;
119+
var child = jObj.Children().FirstOrDefault(x => string.Equals(x.Path, name, StringComparison.InvariantCultureIgnoreCase));
120+
if (child == null) return;
121+
jObj.Remove(child.Path);
110122
}
111123

112-
public static IEnumerable<string> GetArray(this JObject jObj, string name)
124+
public static JToken ToCamelCase(this JToken token)
113125
{
114-
if (!jObj.ContainsKey(name))
126+
if(token.Type == JTokenType.Object) return JObject.FromObject(token.ToObject<ExpandoObject>(), JsonSerializer.Create(new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }));
127+
if(token.Type == JTokenType.Array)
115128
{
116-
return new string[0];
129+
var result = new JArray();
130+
foreach (JToken record in (token as JArray)) result.Add(record.ToCamelCase());
131+
return result;
117132
}
118133

119-
var jArr = jObj[name] as JArray;
120-
if (jArr == null)
121-
{
122-
return new string[0];
123-
}
124-
125-
return jArr.Values<string>().ToList();
134+
return token;
126135
}
127136
}
128137
}

src/Scim/SimpleIdServer.Scim/Extensions/SCIMRepresentationExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ private static bool TryGetExternalId(PatchOperationParameter patchOperation, out
462462
}
463463

464464
var jObj = patchOperation.Value as JObject;
465-
if (patchOperation.Path == StandardSCIMRepresentationAttributes.ExternalId && patchOperation.Value.GetType() == typeof(string))
465+
if (patchOperation.Path == StandardSCIMRepresentationAttributes.ExternalId &&
466+
(patchOperation.Value.GetType() == typeof(string) || patchOperation.Value.GetType() == typeof(JValue)))
466467
{
467468
externalId = patchOperation.Value.ToString();
468469
return true;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) SimpleIdServer. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Linq;
5+
using SimpleIdServer.Scim.DTOs;
6+
using SimpleIdServer.Scim.Extensions;
7+
using System;
8+
using System.Reflection;
9+
10+
namespace SimpleIdServer.Scim.Infrastructure.Converters
11+
{
12+
public class PatchOperationParameterConverter : JsonConverter
13+
{
14+
public override bool CanConvert(Type objectType)
15+
{
16+
return objectType.GetTypeInfo().Equals(typeof(PatchOperationParameter).GetTypeInfo());
17+
}
18+
19+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
20+
{
21+
var json = JObject.Load(reader);
22+
var result = new PatchOperationParameter
23+
{
24+
Path = json.GetStringIgnoreCase(SCIMConstants.PathOperationAttributes.Path)
25+
};
26+
if (json.TryGetEnumIgnoreCase(SCIMConstants.PathOperationAttributes.Operation, out SCIMPatchOperations op))
27+
result.Operation = op;
28+
if (json.TryGetValue(SCIMConstants.PathOperationAttributes.Value, StringComparison.InvariantCultureIgnoreCase, out JToken val))
29+
result.Value = val.ToCamelCase();
30+
return result;
31+
}
32+
33+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
34+
{
35+
}
36+
}
37+
}

src/Scim/SimpleIdServer.Scim/Infrastructure/Converters/RepresentationParameterConverter.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
2222
var jo = JObject.Load(reader);
2323
var result = new RepresentationParameter
2424
{
25-
ExternalId = jo.GetString(StandardSCIMRepresentationAttributes.ExternalId),
26-
Schemas = jo.GetArray(StandardSCIMRepresentationAttributes.Schemas)
25+
ExternalId = jo.GetStringIgnoreCase(StandardSCIMRepresentationAttributes.ExternalId),
26+
Schemas = jo.GetArrayIgnoreCase(StandardSCIMRepresentationAttributes.Schemas)
2727
};
28-
jo.Remove(StandardSCIMRepresentationAttributes.Schemas);
29-
jo.Remove(StandardSCIMRepresentationAttributes.ExternalId);
30-
result.Attributes = jo;
28+
jo.RemoveIgnoreCase(StandardSCIMRepresentationAttributes.Schemas);
29+
jo.RemoveIgnoreCase(StandardSCIMRepresentationAttributes.ExternalId);
30+
result.Attributes = jo.ToCamelCase() as JObject;
3131
return result;
3232
}
3333

0 commit comments

Comments
 (0)