-
Notifications
You must be signed in to change notification settings - Fork 497
Ability to set accessgroup on secure storage. Fixes #712 #1351
Conversation
mattleibow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good at first glance. Will re review tomorrow 😁
|
Lovely! Haven't tested it... so probably need a real test on it :) |
|
Hi guys, |
|
I have been trying to get this to work without luck. A couple of weird issues.
I feel like I'm missing something, but haven't figured it out yet. I had to apply these changes manually, because the branch doesn't appear for me, so maybe I missed something :/ Edit: Yes. For some reason, I could not get VS provisioning to properly select the correct profile and it constantly reverted to wildcard with the Xamarin Essentials project. After re-creating the provisioning stack from scratch and using manual provisioning, I was able to get the tests to pass, but only on a physical device. Even with the proper entitlements and provisioning profile set, you cannot test this in the simulator (which I kind of assumed). I am still trying to get the second issue resolved -- where accessing a previously set key returns the expected result and not a null. Will update my post if/when I figure it out. |
|
Can anyone else incorporate these changes and see if they can set and get a value from two separate code sections? I'm thinking right now that it's my building of Essentials that is at fault. When I use SecureStorage without the acccessGroup I have the same issue. I reverted these changes and had the same issue. But when I grab essentials from Nuget, it works correctly. Would be great to confirm if it's just me. |
|
It did build a nuget -> https://dev.azure.com/xamarin/public/_build/results?buildId=24379&view=logs&j=7868e7c0-c859-51b7-c3be-08c48f6833d0 That you could test. Although like I said I haven't tested it at all yet. |
|
Thank you for replying! My preliminary tests with the nuget are looking good. So far, I have confirmed that I am able to:
This was in a simple, single test app. My next test is to try it out with a container app/extension combination and see if they can share the data. Will post again when that is complete. Thanks again. |
|
Can't seem to get the prerelease to install on my iOS extension project. I'm getting the dreaded "System.drawing/common not in GAC" error and haven't been able to find a resolution that works. Will try again later. |
|
On your extension can you convert it to use package references instead of packages.config? https://docs.microsoft.com/en-us/nuget/consume-packages/migrate-packages-config-to-package-reference |
|
Thanks. I couldn't -- the option was missing. I recreated the project and all is well. All of my other projects were already package references, so not sure what was going on. /shrugs In any case, my container app test appears to work correctly. Just finishing up testing the extension now and will hopefully update with results later today. Edit: For testing, I have a function that is the same identical function that is called in the container app and the extension app. It does a single call to SecureStorage.GetAsync() with an access group. When ran by the container app, it works great. When called by the extension app, it appears that the call is failing for some reason. Still digging... Edit: When using SecureStorage in the ViewDidLoad() method of my extension, it doesn't crash. For some reason though, it crashes when it's used deeper down (specifically, when I use it in an instantiated object from another referenced project). The error is interesting:
Edit: I did some tests moving the GetAsync() up the chain a bit in my iOS extension app. Interestingly, when I call it a little earlier, I get a NULL value instead of a crash/error. All of this works great in my main container app. To be a little more clear:
I'm probably going to try and create a bare-bones extension app to eliminate all variables. I think there's a nuance here that I'm missing, but I haven't yet been able to put my finger on it. |
|
I've finally had some time to create a very simple iOS container app and extension project to test and confirm my earlier findings:
As in my previous tests, everything works as expected in the main app (even across sleeps and force quits), but from the extension app it always returns a NULL value. Which is the same behavior as when you don't include the accessGroup. In reverse it's the same -- secure storage keys created in the extension are only accessible in the extension and not in the container app. I'm really hoping that someone else can discover something or show that it does work between apps like this, but for now I'm going to have to say that this update sadly doesn't quite work. :( -- It's a bit of a chore to test this since it has to be on a device, but if anyone else is interested in playing around with the test app/extension, I guess I could put it up on github. You'll have to set up a handful of provisioning stuff (appIDs, appGroupIDs, etc) to get it working though, so it's not as simple as just running it. Let me know. |
| public static Task<string> GetAsync(string key) | ||
| // Special alias needed to used grouping | ||
| internal static string GetAlias(string accessGroup) | ||
| => string.IsNullOrWhiteSpace(accessGroup) ? Alias : $"{accessGroup}.{Alias}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, do we really want to use $"{accessGroup}.{Alias}" here? I'm just thinking if I was writing my app I might expect the string to be exactly what I pass in. I'm torn of course because adding the Alias does keep it unique to Essentials' usage, but that might defeat the purpose of specifying an access group in the first place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to me. Although, perhaps there's a case that Alias should also be configurable. Perhaps if I have a suite of apps written in different tech stacks, yet they should have a common shared storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I understanding correctly that in the case of app groups, this means that you would need to provision a group in the format of:
<group.groupName>.<packageName>.xamarinessentials
And wouldn't this also mean that sharing secure storage between two apps would be impossible because the package name (distinct between apps) that is added as part of Alias would always be different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kiddailey is correct... Why do we have the package name in there? Aren't prefs already unique to the app?
Maybe the access group should be the override for that?
Also, since things are shared on ios between the app/extension, what is the equivalent for Android? Does it just use the fact that a watch app is the same as a mobile? Is there a communication mechanism?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kiddailey is correct... Why do we have the package name in there? Aren't prefs already unique to the app?
Maybe the access group should be the override for that?
Thanks for pointing this out @mattleibow. You are correct that the access group should override, and it actually does that in the Android implementation. iOS just needs to as well. And the package name cannot be part of it. See my post below detailing why.
|
Apologies for the slow and long-winded response, but I wanted to make sure I really understood what was going on and document it here for reference. In any case, I've finally had time to determine why this update was not working on iOS and what changes are required. The issue basically boils down to two simple factors:
For some basic background -- According to the Xamarin SecureStorage Platform Implementation Specifics for iOS:
This service value is populated by the Alias key defined in SecureStorage.shared.cs (line 9): Issue 1: iOS is not using the GetAlias() method and should be In the iOS implementation, the code directly accesses the internal static Alias rather than using the GetAlias() method. I believe this may have just been an oversight and is easily resolved. More on why iOS should be using this method is covered in Issue 2. Issue 2: The Alias returned by GetAlias() cannot be bundle specific when an access group is provided iOS Apps and/or Extensions do not share bundle IDs and the static Alias will be different between the apps. Because this app-specific Alias is being used as the SecRecord Service Value on iOS, the apps will not be able to access each others' stored values even if the access groups are the same. In my tests, as long as all apps have the same SecRecord Service value and matching access groups/keychain access, SecureStorage works across them as expected. Solution I have confirmed that changing the GetAlias() method as follows and replacing all instances of direct access to Alias in the iOS platform specific code with calls to it, solves the issues with access groups and shared storage on iOS: It is also worth noting that during the course of figuring this out, I stumbled upon a few places (lines 176, 234, and 258) in the Android platform that also directly access Alias. I'm not sure if that was intentional, but additional review/work may be required there as well. Let me know if you'd like me to submit any of the code changes for review somehow. If it's easiest, I can simply create my own pull request using this as a baseline. Lemme know. |
|
@jamesmontemagno Is there something I can do to help get this moving again? Don't want to step on any toes or do things incorrectly. Any guidance is appreciated. I've spent a few weeks testing my changes I mentioned above on iOS and it works perfectly between apps and extensions. |
|
Do you want to send a PR down to my branch? |
* Don't use bundle-specific aliases for secure storage groups * Use GetAlias on iOS to prevent bundle-specific access groups for secure storage * Update to not call GetAlias * Update SecureStorage.ios.tvos.watchos.macos.cs Co-authored-by: James Montemagno <james.montemagno@gmail.com>
|
Unless you think otherwise James, I don't think this will make it in anymore. Thanks everyone for the time and effort on this one! |
Description of Change
Initial test run at adding AccessGroup for Secure storage. will pass this down to Apple Platform Keychain.
Android/UWP just update the Alias for a special group, which seems legit.
Tizen, nothing different.
Bugs Fixed
Provide links to issues here. Ensure that a GitHub issue was created for your feature or bug fix before sending PR.
API Changes
Added new parameters to all methods to pass down a string. Still backwards compatible.
Behavioral Changes
None from previous versions.
PR Checklist