We have created a SCIM integration using
microsoft.systemForCrossDomainIdentityManagement
nuget package which has been described in here:
We have tested the APIs using Postman and they work as they should but when we test them with Azure AD the patch requests fail.
Looking at the logs and narrowing them down we figured that the request is not in the same format as what microsoft.systemForCrossDomainIdentityManagement expects.
One patch request from AD is like below (which will fail):
{ "schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ {"op":"Replace","path":"displayName","value":" User X"} ]}
While the request that works is like this:
{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"] ,
"Operations":[ {"op":"Replace","path":"displayName","value":
[ {"$ref":null,"value":"User x"}]}]
}}
How should we fix this?
The Nuget package take the request and deliver the IPatchRequest so the request doesn't even receive to our part of the code and both parts are Microsoft :|
Since there was no answer from Microsoft after more than a month, they only other way that I know to fix this is to intercept the call before it gets to Microsoft's part of the code (using a middle ware) and change it to the format that they are expecting :\
I have discussed the problem and the solution further in the link below, but I am still waiting for a fix from Microsoft :\ http://pilpag.blogspot.com/2019/02/enabling-scim-using-microsoftsystemforc.html
The easy fix is like this:
public class PatchRequestUpdaterMiddleware : OwinMiddleware
{
private const string OperationValueFinderRegex = "({[\\s\\w\":,.\\[\\]\\\\]*op[\\s\\w\":,.\\[\\]\\\\]*\"value\"\\s*:\\s*)(\"[\\w\\s\\-,.@?!*;\'\\(\\)]+\")"; //{"op":"x","value":"Andrew1"}
public override async Task Invoke(IOwinContext context)
{
if (context.Request.Method.ToLower() != "patch")
{
await Next.Invoke(context);
return;
}
var streamReader = new StreamReader(context.Request.Body);
string body = streamReader.ReadToEnd();
body = Regex.Replace(body, OperationValueFinderRegex, m => $"{m.Groups[1].Value}[{{\"value\":{m.Groups[2].Value}}}]"); //{"op":"x","value":"Ashkan"} ==>> {"op":"x","value":[{"value":"Ashkan"}]}
context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes(body));
await Next.Invoke(context);
}
}
And just add this to the provider that you have created:
class myProvider:ProviderBase
{
....
private void OnServiceStartup(IAppBuilder appBuilder, HttpConfiguration configuration)
{
...
appBuilder.Use<PatchRequestUpdaterMiddleware>();
...
}