Azure User/Group provisioning with SCIM problem with boolean values - azure

I have written an application compliant to the SCIM standard (https://www.rfc-editor.org/rfc/rfc7644), but integrating with Azure I can see that it fails to update a user if it is disabled, the request that Azure send is the following:
PATCH /Users/:id
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
],
"Operations": [
{
"op": "Replace",
"path": "active",
"value": "False"
}
]
}
The SCIM protocol "sais" that the attribute active accept boolean values (https://www.rfc-editor.org/rfc/rfc7643#section-4.1.1), so following the PATCH protocol (https://www.rfc-editor.org/rfc/rfc6902#section-4.3) I expect a boolean value not a string with a boolean written inside it, so the expected request is the following:
PATCH /Users/:id
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
],
"Operations": [
{
"op": "Replace",
"path": "active",
"value": false
}
]
}
So the problem is that the given value "False" should be false.
Is this a bug of Azure or am I missing something? If it is a bug, should I try to parse the string and eventually extract a boolean? But if I do that I'm going to be out of standard. How did you manage this problem?

I also spent a lot of time trying to figure out if Azure was being compliant with the SCIM spec and the answer is that they are not.
The default values that they send for PATCH requests are indeed strings, not booleans as the User JSON schema defines.
You can override the values that get send/mapped into the SCIM schema by:
Go into your provisioning app
Mappings > Synchronize Azure Active Directory Users to customappsso (the name here might be different in your directory)
Find Switch([IsSoftDeleted], "False", "True", "True", "False")
Replace with Switch([IsSoftDeleted], , false, true, true, false) (note the additional comma.)
Hit OK and SAVE
NOTE that after saving it will still see quotes around the booleans, but the PATCH request will be sent correctly.
See screenshots for reference

The default Azure implementation of SCIM isn't fully compliant with the required SCIM schema.
I found I was able to use the default NOT([IsSoftDeleted]) by using Microsoft's workaround which does aim to be SCIM compliant for PATCH operations (returns booleans rather than strings for the 'active' attribute).
This is achieved by appending the URL parameter ?aadOptscim062020 after the tenant url input.

Related

presetOverride when creating Azure Media Services v3 Job

When creating an Azure Media Services Job via the REST API, I cannot set a presetOverrides property on the JobOutputAsset as defined in the documentation: https://learn.microsoft.com/en-us/rest/api/media/jobs/create#joboutputasset
My request body is:
{
"properties": {
"input": {
"#odata.type": "#Microsoft.Media.JobInputAsset",
"assetName": "inputAsset"
},
"outputs": [
{
"#odata.type": "#Microsoft.Media.JobOutputAsset",
"assetName": "outputAsset",
"label": "en-US",
"presetOverride": {
"#odata.type": "#Microsoft.Media.AudioAnalyzerPreset",
"audioLanguage": "en-US",
"mode": "Basic"
}
}
],
"priority" : "Normal"
}
}
The error message thrown is:
{
"error": {
"code": "InvalidResource",
"message": "The property 'presetOverride' does not exist on type 'Microsoft.Media.JobOutputAsset'. Make sure to only use property names that are defined by the type."
}
}
When removing the presetOverride data, everything works as expected. The official documentation clearly states that the Microsoft.Media.JobOutputAsset does have a presetOverride property though. What am I doing wrong?
It is important to select the correct API version when communicating with the Azure Media Services REST API.
In this case, api version 2020-05-01 from the Azure Media Services Postman examples was used. But the presetOverride option is only available starting with version 2021-06-01.
Setting api-version=2021-06-01 as a GET parameter enables Preset Overrides.
couple of concerns here Rene. I would not recommend using the raw REST API directly for any Azure services. Reason being is that there are a lot of built-in retry scenarios and retry policies that are already rolled into the client SDKs. We've had many customers try to roll their own REST API library but run into massive issues in production because they failed to read up on how to handle and write their own custom retry policy code.
Unless you are really familiar with rolling your own retry policies and how Azure Resource Management gateway works, try to avoid it and just use the official client SDKs - see here - https://learn.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#general-rest-and-retry-guidelines
Now, to answer your specific question - try using my sample here in .NET and see if it answers your question.
https://github.com/Azure-Samples/media-services-v3-dotnet/blob/3ab85647cbadd2b868aadf175afdede67b40b2fd/AudioAnalytics/AudioAnalyzer/Program.cs#L129
I can also provide a working sample of this in Node.js/Typescript in this repo if you like. It is using the latest 10.0.0 release of our Javascript SDK.
I'm working on samples in this repo today - https://github.com/Azure-Samples/media-services-v3-node-tutorials
UPDATE: Added basic audio in Typescript sample.
https://github.com/Azure-Samples/media-services-v3-node-tutorials/blob/main/AudioAnalytics/index.ts
Shows how to use the preset override per job.

Azure Search, listAdminKeys, ARM output error (does not support http method 'POST')

I am using this bit of code as an output object in my ARM template,
"[listAdminKeys(variables('searchServiceId'), '2015-08-19').PrimaryKey]"
Full text sample of the output section:
"outputs": {
"SearchServiceAdminKey": {
"type": "string",
"value": "[listAdminKeys(variables('searchServiceId'), '2015-08-19').PrimaryKey]"
},
"SearchServiceQueryKey": {
"type": "string",
"value": "[listQueryKeys(variables('searchServiceId'), '2015-08-19')[0]]"
}
I receive the following error during deployment (unfortunately, any error means the template deployment skips output section):
"The requested resource does not support http method 'POST'."
Checking the browser behavior seems to validate the error is related to the function (and, it using POST).
listAdminKeys using POST
How might I avoid this error and retrieve the AzureSearch admin key in the output?
Update: the goal of doing this is to gather all the relevant bits of information to plug into other scripts (.ps1) as parameters, since those resources are provisioned by this template. Would save someone from digging through the portal to copy/paste.
Thank you
You error comes from listQueryKeys, not admin keys.
https://learn.microsoft.com/en-us/rest/api/searchmanagement/adminkeys/get
https://learn.microsoft.com/en-us/rest/api/searchmanagement/querykeys/listbysearchservice
you wont be able to retrive those in the arm template, it can only "emulate" POST calls, not GET
With the latest API version, it's possible to get the query key using this:
"SearchServiceQueryKey": {
"type": "string",
"value": "[listQueryKeys(variables('searchServiceId'), '2020-06-30').value[0].key]"
}

Get route url for a http triggered functions in an ARM template

I'm trying to figure out how to get the route for an HTTP triggered Azure Function within an ARM template.
Thanks to a blog post I managed to find out the listsecret command, but when trying to execute this action via powershell, the output doesn't give me the trigger_url I was expecting. The URL does not comply with the configured route of the function, and shows the default trigger if no route would have been configured.
Any way I can get a hold of the configured route instead since I can't seem to use the trigger_url.
My configured route has got parameters in the path as well, e.g.:
{
"name": "req",
"type": "httpTrigger",
"direction": "in",
"authLevel": "function",
"methods": [
"POST"
],
"route": "method/{userId}/{deviceId}"
}
The output of listsecrets is:
trigger_url: https://functionapp.azurewebsites.net/api/method?code=hostkey
Is there any other way to extract the host key and route?
Try playing with the API version, but I would suspect that this is not possible as of now.
Currently, the only way to get the route is by reading the function.json file and parsing that information out, which you can do by using Kudu's VFS API.
For the keys, I would actually recommend using the key management APIs instead of listSecrets. As the latter is meant to address a small set of scenarios (primarily to enable some internal integrations) where the key management API more robust API and will continue to work with different secret storage providers (e.g. Azure Storage, which is what is used when slots are enabled and will eventually become the default).

Access user data in AWS lambda function with custom authorizer

I got a nodeJS lambda function which returns database data and I'd like to filter that data based on the user. I created a custom authorizer lambda function which gets the user for a JWT token, but I couldn't find a way to pass data from the authorizer function to the database function, except for principalId (user.id).
What possibilities do I have here? Do I need to setup cognito? Or is there another possibility?
While reading documentation I found out something different from what the accepted answer suggests. Maybe it's new, but now output can include not only a principalId, but also a "context", which is an object. Sample:
{
"principalId": "xxxxxxxx", // The principal user identification associated with the token send by the client.
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow|Deny",
"Resource": "arn:aws:execute-api:<regionId>:<accountId>:<appId>/<stage>/<httpVerb>/[<resource>/<httpVerb>/[...]]"
}
]
},
"context": {
"key": "value",
"numKey": 1,
"boolKey": true
}
}
More from official documentation here. Much better aproach. :)
It seems you have a couple of options.
1) You can place all the information about the user you need into the principal id that is set in the custom authorizer function. So maybe you could serialize the user as json or if you need just a couple of ids then concatenate them together with special character like: principalId: "userId|organizationId". I believe that there is some caching that API Gateway does around that principal id that is returned so I wouldn't make it anything that could be highly dynamic. You could also turn off caching for authorization as well, but that would slow down that endpoint as a result.
2) Just pass the user id and do the user lookup again to get all the information in the function that does the database call. If you're using DynamoDB it will be fast supposedly.
And Cognito seems nice but I don't think it will help you solve the particular problem that you're having now. If it was me though I would choose option 2.
One possible way is to encode the data object to base64 string from authorizer lambda function and decode it down the line.
var principalId = new Buffer(JSON.stringify({
id: 5,
name: "John"
})).toString('base64');
var policy = require('./policy.json');
var policyConfig = {
"principalId": principalId,
"policyDocument": policy
};
context.succeed(policyConfig);
Decoding can be done in two places, one place is the request template section. This can be done by writing a transformation in velocity scripts as shown below
{
"requestTemplate": {
"application/json": {
"principal": "$util.urlEncode($util.base64Decode($context.authorizer.principalId))"
}
}
}
Other option is to decode inside the endpoint lambda function with the nodejs Base64 decoding. Check the following link for more information.
stack overflow answer for base64 decode

unable to configure a permission role in RavenDB

looking for some help or a blog post really regarding using the auth bundle with RavenDB..
using the HelloWorld example: http://ravendb.net/tutorials/hello-world
i'm trying to disable the user from querying for orders.. i've tried different auth roles approaches but i can't get the damn thing to work.
at present i've:
* created a authorization user
* created a authorization role
Id: Authorization/Roles/Orders
{
"Permissions": [
{
"Operation": "order/1",
"Tags": [
"Orders"
],
"Allow": false,
"Priority": 1
}
]
}
ID: Authorization/Users/ayende
{
"Name": "Ayende Rahien",
"Roles": [
"Authorization/Roles/Orders"
]
}
just can't get my head around how to filter out the orders from queries.
for example, querying orders/1 will return an order of 1 prior to applying the permission.
after using:
session.SecureFor("Authorization/Users/ayende", "orders/1");
I would expect orders to return no orders..
do i have this concept totally wrong or just configured my permission's wrong?
thanks
You can use the IsAllowed method to check whatever or not you can access a document or now, but also to check why you can / can't access a document.
Have you applied your permission to the document then invoked SaveChanges? Maybe if you post your code it would easier to tell what's happening.

Resources