-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues using Resource Authorization Tokens #441
Comments
I did a deep-dive into the module's code today and I think I've found the issue. In the Get-CosmosDbAuthorizationHeadersFromContext util the code checks for a valid token where the token's resource matches the resource you are querying: CosmosDB/source/Private/utils/Get-CosmosDbAuthorizationHeadersFromContext.ps1 Lines 23 to 25 in f6d628c
When creating a token, the resource connected to the token looks like CosmosDB/source/Private/utils/Invoke-CosmosDbRequest.ps1 Lines 144 to 155 in f6d628c
If no master key is set, the query fails. I believe it should allow sub resources in the token check and that this is an issue in the module code. Looking at Invoke-CosmosDbRequest, we actually seem to have all the data we need to make this work. The CosmosDB/source/Private/utils/Invoke-CosmosDbRequest.ps1 Lines 128 to 136 in f6d628c
I attempted a fix: # Generate the resource link value that will be used in the URI and to generate the resource id
switch ($resourceType)
{
'dbs'
{
# Request for a database object (not containined in a database)
if ([System.String]::IsNullOrEmpty($ResourcePath))
{
$ResourceLink = 'dbs'
$AuthLink = 'dbs' # +++
}
else
{
$resourceLink = $ResourcePath
$resourceId = $resourceLink
$authLink = $resourceId # +++
}
}
'offers'
{
# Request for an offer object (not contained in a database)
if ([System.String]::IsNullOrEmpty($ResourcePath))
{
$ResourceLink = 'offers'
$AuthLink = 'offers' # +++
}
else
{
$resourceLink = $ResourcePath
$resourceId = ($ResourceLink -split '/')[1].ToLowerInvariant()
$authLink = $resourceId # +++
}
}
default
{
# Request for an object that is within a database
$resourceLink = ('dbs/{0}' -f $Database)
if ($PSBoundParameters.ContainsKey('ResourcePath'))
{
$resourceLink = ('{0}/{1}' -f $resourceLink, $ResourcePath)
}
else
{
$resourceLink = ('{0}/{1}' -f $resourceLink, $ResourceType)
}
# Generate the resource Id from the resource link value
$resourceElements = [System.Collections.ArrayList] ($resourceLink -split '/')
if (($resourceElements.Count % 2) -eq 0)
{
$resourceId = $resourceLink
}
else
{
$resourceElements.RemoveAt($resourceElements.Count - 1)
$resourceId = $resourceElements -Join '/'
}
$authLink = $resourceId # +++
}
}
# Generate the URI from the base connection URI and the resource link
$baseUri = $Context.BaseUri.ToString()
$uri = [uri]::New(('{0}{1}' -f $baseUri, $resourceLink))
# Try to build the authorization headers from the Context
$authorizationHeaders = Get-CosmosDbAuthorizationHeadersFromContext `
-Context $Context `
-ResourceLink $authLink # changed from $resourceLink to $authLink In the above code I've simply added the TLDR / Summary Considering the resource tokens are not a new feature, and this seems like a pretty big issue that prevents them from being all that useable, I could be way off target. I suspect this isn't a commonly used part of the module but I'm still surprised the issue hasn't come up before. Have I missed something? |
Hi @chrisjantzen - thank you for raising this and all the investigation. You're right - this doesn't get a lot of use, but I think it is covered by the automated integration tests. Let me spend some time this weekend digging into the desired function of this feature and see if I've made some mistakes. What I'm scratching my head over is why the resource token context link doesn't match the query context link? E.g. Usage vs DeviceUsage? Do you know why that is happening? Seems like they're reporting as different databases. |
Thanks you very much @PlagueHO! That part's my bad. I created the test database 'Usage' and my testing was split between a live 'DeviceUsage' and test 'Usage' DB. They were setup the same way so the data should all match. I've updated the post so that it all references the same database now. |
I've been using a modified module based on the above code and found an issue with it. This does not work when updating documents as the path contains 6 parts (and therefore it's even so the resource ID doesn't get stripped down). It seems like the authLink should always be the first 4 parts of the resource link as that should always equated to the collection itself. This is a modification to the 'default' section of the switch in Invoke-CosmosDBRequest in the above code. default
{
# Request for an object that is within a database
$resourceLink = ('dbs/{0}' -f $Database)
if ($PSBoundParameters.ContainsKey('ResourcePath'))
{
$resourceLink = ('{0}/{1}' -f $resourceLink, $ResourcePath)
}
else
{
$resourceLink = ('{0}/{1}' -f $resourceLink, $ResourceType)
}
# Generate the resource Id from the resource link value
$resourceElements = [System.Collections.ArrayList] ($resourceLink -split '/')
if (($resourceElements.Count % 2) -eq 0)
{
$resourceId = $resourceLink
}
else
{
$resourceElements.RemoveAt($resourceElements.Count - 1)
$resourceId = $resourceElements -Join '/'
}
# Generate the collection's path for token auth purposes
if ($resourceElements.Count -le 4)
{
$authLink = $resourceId
}
else
{
$authLink = $resourceElements[0..3] -Join '/'
}
} This just uses the resourceLink unless it has greater than 4 parts, and in that case it takes the first 4 parts of the path. I've tested this with gets, sets, and inserts so far. |
I am trying to setup a key broker and am struggling to get it working. I used the example to setup a User and configured a Permission on that user, this seemed to work smoothly, I then create a Resource Auth Token but when using the Resource Context I am getting an error. Here is the code I have used so far:
The TimeStamp is the main thing done differently from the example but I found the example didn't work quite right and this seemed to work well enough as a workaround. I also hardcoded the resource path, but I have also tested
Get-CosmosDbCollectionResourcePath
and end up with the same result.This all appears to work and creates a context object with the Token set:
If I try to use this context object to get the Users collection's info like in the example it works fine, but if I try to query documents I get an error.
This works:
Get-CosmosDbCollection -Context $resourceContext -Id 'Users'
This does not:
It returns the following error:
VERBOSE: Searching context tokens for resource matching 'dbs/Usage/colls/Users/docs'.
VERBOSE: Context token with resource 'dbs/Usage/colls/Users/docs' not found.
System.InvalidOperationException: The authorization key is empty. It must be passed in the context or a valid token context for the resource being accessed must be supplied.
If anyone has any suggestions or could point me in the right direction, I'd really appreciate it! I've went through the code but can't figure out why it's not working. It seems like the permission's aren't correct for this. I did try setting a permission on the resource
dbs/Usage/colls/Users/docs
, but it wouldn't take that as a valid option.The text was updated successfully, but these errors were encountered: