SCIM Deserialization Issue in .NET - c#

As a newcomer to the SCIM (System for Cross-domain Identity Management) standard, please excuse any ignorance as I'm on the learning curve trying to figure out how to make clean/simple requests to provision users, delete users and modifiy users.
I'm attempting to use C#/.NET to make HTTP REST requests for a user via SCIM, using the System.Net.Http.HttpClient
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.110).aspx
I can do this successfully and get a JSON response from the server, however in order to easily read the response object and manipulate it, I want to deserialize it.. After much reading around trying to use things like JsonConvert, dynamic etc. I stumbled upon a Microsoft nuget library which seemed to hint at being useful. Sadly there don't appear to be any docs for it*
UPDATED:
One of the authors has updated the nuget page with a link to a blog post which goes some way to explaining usage.
Microsoft.SystemForCrossDomainIdentityManagement
https://www.nuget.org/packages/Microsoft.SystemForCrossDomainIdentityManagement/
The SCIM provider I'm attempting to get data from is Facebook, using the example they publish on their site for getting a user by email:
https://developers.facebook.com/docs/facebook-at-work/provisioning/scim-api#getuserbyemail
Here's a code sample in C# which attempts to get the user from the SCIM service and deserialize them. I'm finding that the queryResponse I get back is deserialized correctly as the properties are populated, however the Core1EnterpriseUser which is the first and only of the resource objects, has null/default properties.
var userName = "foo.bar#foobar.com";
var response = await client.GetAsync($"Users?filter=userName%20eq%20%22{userName}%22");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var jsonResponseProperties = await Task.Factory.StartNew(() => { return JsonConvert.DeserializeObject<Dictionary<string, object>>(json); });
var userFactory = new QueryResponseJsonDeserializingFactory<Core1EnterpriseUser>();
var queryResponse = userFactory.Create(jsonResponseProperties);
if (queryResponse.TotalResults == 1)
{
var user = queryResponse.Resources.First();
var id = user.Identifier; // this and other properties are null/false etc.
}
}
Here's a sample of the JSON that is returned by the service when I query it:
{
"schemas": [
"urn:scim:schemas:core:1.0"
],
"totalResults": 1,
"itemsPerPage": 10,
"startIndex": 1,
"Resources": [
{
"schemas": [
"urn:scim:schemas:core:1.0",
"urn:scim:schemas:extension:enterprise:1.0",
"urn:scim:schemas:extension:facebook:starttermdates:1.0",
"urn:scim:schemas:extension:facebook:suppressclaimemail:1.0"
],
"id": 180383108978226,
"userName": "foo.bar\u0040foobar.com",
"name": {
"formatted": "Foo Bar",
"familyName": "Bar",
"givenName": "Foo"
},
"title": "Vice President",
"active": true,
"emails": [
{
"primary": false,
"type": "work",
"value": "foo.bar\u0040foobar.com"
}
],
"urn:scim:schemas:extension:enterprise:1.0": {
"department": "IT"
},
"urn:scim:schemas:extension:facebook:starttermdates:1.0": {
"startDate": 0,
"termDate": 0
}
}
]
}
UPDATE:
I'm in dialog with one of the authors of the project and he kindly pointed me at this blog post:
http://blogs.technet.com/b/ad/archive/2015/11/23/azure-ad-helping-you-adding-scim-support-to-your-applications.aspx
He has also updated the nuget library which now includes support for v1 of SCIM, also pointing out that as the JSON data suggests the version used by Facebook is v1: "urn:scim:schemas:core:1.0" so now I can use Core1 rather than attempting to use Core2 classes (I've updated the question above to use Core1EnterpriseUser).
I'm still not able to get my response deserialized correcty at present and will update the question with more information as I have it.
Again, I don't have to use this library if it becomes apparent that it's not easily going to work, as I know the brief description on nuget suggests it was created for Azure AD.
However I'd appreciate any advice on how this type of thing could/should be done as I'm sure there must be a lot of people out there using SCIM - how do you parse your responses/generate your requests such that you have actual objects? Can you automatically parse responses for schemas in order to augment the object with the correct properties?
I was up late last night hand crafting some model classes to handle the response objects - which I do seem to have working. If I can't get the nuget library working (the preferred option) then I'll have to go with my own. :/
Thanks again
peteski

Although I'm still none the wiser about best practices with SCIM, I've managed to get the code working now - with massive thanks to one of the nuget library's authors Craig McMurtry at Microsoft!
There were a few things to iron out along the way, such as the nuget package being updated to include the previous support for older v1 SCIM objects. But here's a snippet of what worked based on the example in my question, but it turned out to be using the Newtonsoft serializer. :(
In the code above the line:
var jsonResponseProperties = await Task.Factory.StartNew(() => { return JsonConvert.DeserializeObject<Dictionary<string, object>>(json); });
Was replaced with:
var jsonResponseProperties = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);
Et voilà! My object's properties are now deserializing...

Related

How do I get the parent folder using the Google Drive API?

I'm trying to write a method that gets the parent folder of the folder whose Id is passed in. I have tried many different variations, most of which come from accepted answers here, but every one causes an exception.
For example, the following code...
public async Task<DriveFile> GetParentFolder(string folderId) {
FilesResource.ListRequest request = _service.Files.List();
request.Q = $"parents contains '{folderId}'";
request.Fields = "*";
FileList files = await request.ExecuteAsync();
return files.Files[0];
}
...throws the following exception...
Error: The service drive has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Invalid Value [400]
Errors [
Message[Invalid Value] Location[q - parameter] Reason[invalid] Domain[global]
]
I have tried many values for the Q and Fields properties, but all result in the same exception.
I have other code working with the API, so it's not the basic service that's a problem, and I've used the API to get the Ids of some folders, so I know I'm passing in a valid value.
One of the problems is that v2 of the API had a Parents list, which looks like it does what I want, but this seems to be missing in v3.
Anyone able to help me? Thanks
Your going about it the wrong way you dont need to use file.list you already have the file id just use file.get.
Lets say i have the folder id here.
{
"kind": "drive#file",
"id": "1bzDkXlcND_yycIcbqwr1YYZ98-Yv7SG7",
"name": "Current Badges (2019-21)",
"mimeType": "application/vnd.google-apps.folder"
},
As you can see in this example i have the id and the mime type is a folder.
All i need to do is do a file.get
var request = _service.Files.Get("1bzDkXlcND_yycIcbqwr1YYZ98-Yv7SG7");
request.Fields = "parents";
var response = request.Execute();
The response will contain a filed called parents which is the parent of the folder.
As you can see if you already know the file id or in this case the folder id. Then you really just need to use file.get to get all the information about that id.
There's really no reason to use file.list.

Gremlin.NET: Execute queries using .Next() raises NullReferenceException

Starting from the Azure Cosmos DB Graph API example:
https://github.com/Azure-Samples/azure-cosmos-db-graph-gremlindotnet-getting-started
I am interested in using Gremlin.NET (the example uses version 3.2.7) to execute queries using the C# classes instead of writing string queries and execute them using the gremlinClient.SubmitAsync<dynamic>("...") method.
But when I execute the following code I'm getting a
NullReferenceException at Gremlin.Net.Driver.Connection.d__14`1.MoveNext()
when calling .Next()
var gremlinServer = new GremlinServer(hostname, port, enableSsl: true,
username: "/dbs/" + database + "/colls/" + collection,
password: authKey);
var graph = new Graph();
var g = graph.Traversal().WithRemote(new DriverRemoteConnection(new GremlinClient(gremlinServer)));
var vertex = g.V().HasLabel("person").Next();
Console.WriteLine(vertex);
Unfortunately I haven't found any documentation on how to use Gremlin.NET it would be nice if someone of you can point me to some "getting started".
Edit:
The query result from the Azure Cosmos DB Data Explorer looks like the following:
[
{
"id": "thomas",
"label": "person",
"type": "vertex",
"properties": {
"firstName": [
{
"id": "9015b584-375f-4005-af00-f49d6e2d6b94",
"value": "Thomas"
}
],
"age": [
{
"id": "c2300d19-12a0-474a-9405-eb89466bcbb3",
"value": 44
}
]
},
"_isRoot": true,
"_isFixedPosition": true
}
]
The reason why this doesn't work with Cosmos DB is simply that Cosmos DB doesn't support Gremlin Bytecode yet which is what is sent to the server when you use the traversal API as you did.
So, your only option currently is to really write the queries as strings and just send those query strings to the server.
Regarding documentation: Gremlin traversals can be written in different languages (see The Gremlin Graph Traversal Machine and Language for more information about Gremlin in general). Therefore the TinkerPop docs also apply to Gremlin.Net and the Gremlin.Net part of the documentation only explains the aspects that are really specific to Gremlin.Net.

Filtering Event Messages using Microsoft Graph REST API

I would like to query only Event Messages from Outlook Mail using the Microsoft GRAPH API. I could not find any information on this in the documentation for Microsoft Graph.
I have tried the following queries on the Graph Explorers, but none worked. It seems like Microsoft Graph does not support the IsOf (which filters the type of an object) filtering option. However, I have found that this feature is supported and documented for Azure GRAPH API.
https://graph.microsoft.com/v1.0/me/messages?$filter=isof('#microsoft.graph.eventMessage') eq true
https://graph.microsoft.com/v1.0/me/messages?$filter=isof('#microsoft.graph.eventMessage')
Does anyone know if the operation I tried to do is supported by the Microsoft Graph API? If not, is there anything else I can do to query only Event Messages?
As URL: Query string parameters states for the $filter parameter:
Indicates which entity types should be included in the response. Optional. The supported entity types are: User, Group and Contact. Only valid when resourceSet is “directoryObjects”; otherwise, resourceSet overrides the filter.
For example,
https://graph.windows.net/contoso.com/directoryObjects?api-version=2013-04-05&$filter=isof('Microsoft.WindowsAzure.ActiveDirectory.User')
For Microsoft Graph, I checked Use query parameters, but did not find any samples. Then, I used Graph Explorer to test this scenario as follows:
I assumed that this operation is not supported by Microsoft Graph API for now. You could add your feature request here. Or you could use the $select query parameter to return a set of properties. Details you could follow here.
The isof can be used with objects with an "#odata.type"
E.g. https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations?$filter=isof('microsoft.graph.windowsUpdateForBusinessConfiguration')
returns
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#deviceManagement/deviceConfigurations",
"value": [
{
"#odata.type": "#microsoft.graph.windowsUpdateForBusinessConfiguration",
"id": "123123-1234-1234-1234-123456789123",
"lastModifiedDateTime": "2022-07-18T10:01:53.713763Z",
"createdDateTime": "2022-07-18T10:01:53.713763Z",
"description": "",
"displayName": "my Name",
...
{
]
}

PayPal Rest API - Update Billing Plan Return URL

I have been using the PayPal Rest API and have successfully created and activated a BillingPlan but I'm having trouble updating said plan's return_url. I think it's something to do with the JSON path I'm using although I'm not sure why!?
Anyway, I am calling the update plan method: https://developer.paypal.com/docs/api/#update-a-plan
A BillingPlan follows the format:
{
"id": "P-94458432VR012762KRWBZEUA",
"state": "ACTIVE",
"name": "T-Shirt of the Month Club Plan",
"description": "Template creation.",
"type": "FIXED",
...
"merchant_preferences": {
"setup_fee": {
"currency": "USD",
"value": "1"
},
"max_fail_attempts": "0",
"return_url": "http://example.com",
"cancel_url": "http://example.com",
"auto_bill_amount": "YES",
"initial_fail_amount_action": "CONTINUE"
},
...
}
I'm using the C# SDK but my request JSON should look very much like:
{
"path": "merchant_preferences",
"value": {
"return_url": "http://example.com/payment/return"
},
"op": "replace"
}
I keep getting responses along the line's of:
{"name":"BUSINESS_VALIDATION_ERROR","details":[{"field":"validation_error","issue":"Invalid
Path provided."}],"message":"Validation
Error.","information_link":"https://developer.paypal.com/webapps/developer/docs/api/#BUSINESS_VALIDATION_ERROR","debug_id":"2ae68f9f0aa72"}
To sum up - I want to change the billing plan return_url from http://example.com to http://example.com/payment/return.
I've changed the path to various things to no avail. Can anyone help??
You cannot update the plan, once it is set to active. The reason for that restriction is that because there could be possible agreements based on that plan, modifying it would affect the already agreed billing agreements.
However, I agree with your problem statement, that changing the Return URL should not be an issue as this is not a part of agreement, but more of a configuration change. It would be nice to somehow allow updating similar settings in Plan, even after active. I will let the API team know about that.
however, in the mean time, there is no way you would be able to do that. Alternatively, you could possibly create a new plan, and use that instead. Not the answer you are looking for, but a probable solution.

How to filter Facebook pages by CREATE_CONTENT permission?

I have the following Graph API call: me/accounts?fields=access_token,name,id,perms that I use to get the page tokens from the user.
Now I would like to filter this by perms="CREATE_CONTENT". How can I filter this Graph API call?
I'm using the C# Facebook.net SDK. Currently I use this code:
client.Post("me/accounts", new { fields = "access_token,name,id,perms" });
Opening caveat: I do not know C#, but I regularly work with the Facebook in other programming languages.
Facebook has a number of "Publish Permissions" as part of its Extended Permissions. I'm assuming you're already requesting one or more of these permissions from your users. (I don't see a create_content listed; that's the only reason I mention it.) Let's say, for example, you requested the create_event permission from your users.
Try accumulating the Facebook User IDs into a list, and then issuing a FQL query using the Facebook SDK client for the permission(s) you're interested in:
List<int> facebookUserIds = new List<int>(1, 2, 3);
var query = string.Format("SELECT uid, create_event FROM permissions WHERE uid IN ({})", string.Join(",", facebookUserIds));
dynamic parameters = new ExpandoObject();
parameters.q = query;
dynamic results = client.Get("/fql", parameters);
The response you receive will have properties like this (here, in JSON format):
{
"data": [
{
"uid": 1,
"create_event": 1
},
{
"uid": 2,
"create_event": 0
}
{
"uid": 3,
"create_event": 0
}
]
}
Of course, 0 means permission denied, and 1 means permission granted for the App ID you're using to authenticate with the Facebook API.
Note: Users will only be returned in the response if they've previously authenticated your app (of the most basic level of permissions); but this shouldn't be an issue.
You can't directly filter this in the API, but it would be quite easy to do from c#- you're getting an ICollection from the Facebook.JSONObject response, so you can just use linq to filter it - Filtering collections in C# has a pretty good explanation of how to achieve this.

Categories