{"id":99,"date":"2011-10-31T01:54:49","date_gmt":"2011-10-31T10:54:49","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/?p=99"},"modified":"2012-01-29T23:41:29","modified_gmt":"2012-01-30T08:41:29","slug":"blobshare-sample-acs-protected-file-sharing","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2011\/10\/31\/blobshare-sample-acs-protected-file-sharing\/","title":{"rendered":"BlobShare Sample: ACS-Protected File Sharing"},"content":{"rendered":"<p align=\"left\">Weather is not that good this Sunday afternoon, and the wife warned me already yesterday that today she was going to catch up with the <a href=\"https:\/\/www.ai-class.com\/\">AI class<\/a>; hence, I think I am going to break the blog-silence and spend some time describing <a href=\"http:\/\/blobshare.codeplex.com\/\">BlobShare<\/a>, a little jewel my DPE friends quietly released last week (and covered during <a href=\"http:\/\/channel9.msdn.com\/Shows\/Cloud+Cover\/Episode-63-Securely-Sharing-Files-with-Windows-Azure\">the latest CloudCover episode<\/a>, no pun intended).<\/p>\n<p align=\"left\">BlobShare is a very nice Windows Azure sample, which demonstrates one way of solving a very concrete problem: how to share large files on the public internet, while maintaining full control over who can access what?<br \/>\nThe usual disclaimers about a sample being a sample apply here, however you\u2019ll be happy to know that DPE has been using an instance of BlobShare for sharing content for many months by now, it started while I was still over there. Many features in BlobShare derive from real usage requirements that emerged while actually using the application. I am <strong><em>so<\/em><\/strong> glad to see they finally managed to release it in a consumable form. Good job <a href=\"http:\/\/www.wadewegner.com\/\">Wade\u2019s<\/a> gang!<\/p>\n<p align=\"left\">Many of the things demonstrated in BlobShare have been featured in other samples: exhibit A, the email invitation system (seen in <a href=\"http:\/\/www.fabrikamshipping.com\/\">FabrikamShipping<\/a>, the <a href=\"http:\/\/waacceleratorumbraco.codeplex.com\/\">Umbraco ACS accelerator<\/a>, etc). However it was always buried within many more moving parts, whereas here it is pretty easy to isolate. I am sure you\u2019ll find it much easier to grok.<br \/>\nThe same holds for various other aspects I am often asked about, like how to integrate an incoming IClaimsIdentity with attributes from a store which is local to the application: BlobShare does it to enable one of its key capabilities, enforcing locally stored permissions, hence the signal\/noise ratio should be blindingly good.<\/p>\n<p>Do watch <a href=\"http:\/\/channel9.msdn.com\/Shows\/Cloud+Cover\/Episode-63-Securely-Sharing-Files-with-Windows-Azure\">the latest CloudCover episode<\/a>, where Wade &amp; Steve properly introduce the <a href=\"http:\/\/blobshare.codeplex.com\/\">project<\/a>, talk about setup, etc etc: here I am (surprise surprise) mostly focusing on the identity &amp; access aspects.<\/p>\n<h1>Overview<\/h1>\n<p>In a nutshell:<\/p>\n<ul>\n<li>BlobShare is an MVC app which sits in front of your blob storage account<\/li>\n<li>The MVC app leverages ACS for admitting users with accounts from any of the identity providers it can trust\u2026\n<ul>\n<li>\u2026but it maintains an application-local (SQL Azure) database of user profiles and roles.\n<ul>\n<li>local user info and roles are used to establish if a given user has access to the blob he\/she is requesting<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Basically, all your blobs live in a <strong>trusted subsystem<\/strong>: only BlobShare can access blobs directly. BlobShare offers individual URLs for every blob, of course, but they are all rooted in the BlobShare app itself. As you try to get to one blob, BlobShare will funnel you through the authentication process and if it turns out you don\u2019t have permissions for that specific blob, you don\u2019t get access.<br \/>\nThat\u2019s pretty handy when you are sharing stuff you want to keep a close eye on: with a shared signature if the URL leaks you\u2019re done, here not only you force authentication, you can even keep a useful audit trail and notice if there\u2019s something fishy going on (if the same user accesses the same content in a small time interval and from many different machines, chances are you have somebody who\u2019s sharing his account).<\/p>\n<p>BlobShare offers a full UI for all the tasks that the flows introduced above entail. Administrators can upload blobs, group multiple blobs in larger sets, create users by sending them an invitation email, assign roles to users, permissions to roles and individual users, and examine a complete audit trail of all the users\u2019 activities. Users can sign up (by responding to an invitation) and access the blobs for which they received permissions for, for as long as those permissions have been deemed valid.<\/p>\n<p>Justo give you a feeling of the kind of things BlobShare keeps track of, below you can find the diagram of its SQL Azure database.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb.png\" alt=\"image\" width=\"626\" height=\"390\" border=\"0\" \/><\/a><\/p>\n<p>As you might notice, all the access control policy is kept in the database. Here ACS is being used to take care of authenticating with all the various trusted IPs: BlobShare\u2019s setup will add the usual IPs, add the BlobShare instance as an RP, and create pass-through rules for all. BlobShare expects ACS to return a normalized token containing just the NameIdentifier and the IdentityProvider claims (take note if you later add custom providers). Those two claims are used to uniquely identify each user in the BlobShare database. There is no concept of pure, un-provisioned federated user here: if the incoming NameIdentifier-IdentityProvider tuple is not present in the db (and associated to the permissions of the blob being requested) the access is denied.<\/p>\n<p>From the access control point of view, there are three (actually, four) different types of requests that are interesting to examine:<\/p>\n<ol>\n<li><strong>Bootstrap<\/strong>, or <strong>Imprinting<\/strong>. The very first time a newly deployed BlobShare instance runs, it will onboard its first Administrator<\/li>\n<li><strong>User redeeming an invitation<\/strong>. One new user received an invitation and is now going through the sign up flow<\/li>\n<li><strong>User accessing a BlobShare URL that points to a blob<\/strong>.<\/li>\n<li><strong>User signing in<\/strong>. Very similar to the above, sans interesting authorization tidbits<\/li>\n<\/ol>\n<p>Instead of discussing those in abstract, we will explore those paths while walking through some typical application use. In a minute.<\/p>\n<p>As you know I have this unhealthy passion for putting together pictures which show as many things at the same time as I can fit in the allotted real estate. That\u2019s great when you already understand the matter, I find it helps me to understand relationships and an architecture as a whole; but while you are learning it might not offer the most gentle slope for ramping up.<br \/>\nWell, below you can find one such diagram: it lists the relevant moving parts in BlobShare that come into play when a request carrying a token shows up.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image1.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb1.png\" alt=\"image\" width=\"600\" height=\"445\" border=\"0\" \/><\/a><\/p>\n<p>Please ignore the details of the flows for now, you can come back to this figure every time we\u2019ll delve in the details of those. The thing I\u2019d like you to observe at this time is how the solution is layered in various elements, each taking care of a specific access control task:<\/p>\n<ul>\n<li>WIF sits in front of the application\n<ul>\n<li>The first layer implements the classic mechanisms of federated authentication: forward the user to the identity provider (or to a broker like ACS, in this case) according to the protocol of choice, verify that incoming tokens are well-formed\/have not been tampered with\/are not expired\/come from the expected authority and so on<\/li>\n<li>The next layer is a ClaimsAuthenticationManager implementation. In BlobShare this an especially important stage, as so much information that is relevant to the incoming user\u2019s identity resides in the RP\u2019s database and needs to be reconciled before the call can go any further. Moreover, which information is relevant changes dramatically between call types (more below)<\/li>\n<li>The last layer before giving control to the application is an implementation of a ClaimsAuthorizationManager. This is a cornerstone in BlobShare, as it represents the enforcement stage for the policies defined through the application flow<\/li>\n<\/ul>\n<\/li>\n<li>The application itself will use the incoming claims to customize what is shown (i.e. every user will see only the blobs he\/she has access to) and for auditing purposes<\/li>\n<\/ul>\n<p>IN the rest of the post I\u2019ll go through BlobShare doing some basic tasks. As the elements and the different requests types come into play I\u2019ll add commentary &amp; take the chance to dig deeper in some of those concepts.<br \/>\nAs I mentioned earlier, those tasks correspond to questions I get very often, hence I suspect that some of you guys will really like some of this stuff <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-style: none;\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/wlEmoticon-smile.png\" alt=\"Smile\" \/><\/p>\n<h1>Imprinting<\/h1>\n<p>Handling the administrator of those sites that use federated identity is always an interesting challenge. How to ensure that once you deployed your site, the administrator can log in and start working right away?<\/p>\n<p>Adding a username\/password is kind of bad form. Every user can reuse existing social accounts, why should the admin be left out? On the other hand, if you want to authenticate the admin with a social account you have the following problems:<\/p>\n<ul>\n<li>at design time you might not know the values (like the nameidentifier) that will be in the authentication token the admin will send. Without those values how can you tell if the incoming user is really the intended admin?<\/li>\n<li>you might not even know which identity provider the admin will want to use: live id? Google? who knows.<\/li>\n<\/ul>\n<p>Sure, one could use also with the admin the classic email invitation flow: after all, we are using it for other users right? Unfortunately it might not be a good idea to take a dependency on a setting that the admin itself might be required to provide (in BlobShare the SMTP server is already set up, but it\u2019s just coincidence: I think that the original plan was to make it configurable on first run).<\/p>\n<p>At the time we toyed with the idea of just making admin the first user who logs in in the newly deployed instance: I like to call this <a href=\"http:\/\/en.wikipedia.org\/wiki\/Imprinting_(psychology)\">imprinting<\/a>, isn\u2019t this a bit like <a href=\"http:\/\/en.wikipedia.org\/wiki\/Konrad_Lorenz\">Konrad Lorentz\u2019s<\/a> ducks? <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-winkingsmile\" style=\"border-style: none;\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/wlEmoticon-winkingsmile.png\" alt=\"Winking smile\" \/><\/p>\n<p>However, even if the probability that a random dude beats you to your deployment, it was still a possibility: hence we devised a schema for which at deployment time you establish a secret, and you are required to provide that secret on first run to associate your social account to the administrator user of that BlobShare\u2019s instance.<\/p>\n<p>Easier to show that to describe! Hit F5 on your local instance, you\u2019ll be brought straight to the page below.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image2.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb2.png\" alt=\"image\" width=\"630\" height=\"437\" border=\"0\" \/><\/a><\/p>\n<p>At the time this page was called sign up: I am not sure why the guys decided to change it, but it works nonetheless. Just sign in using whatever account you prefer.<\/p>\n<p>You\u2019ll go through the usual dance with your IP and ACS, then land on the page below.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image3.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb3.png\" alt=\"image\" width=\"632\" height=\"444\" border=\"0\" \/><\/a><\/p>\n<p>Add the email you want to use, provide the secret and\u2026<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image4.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb4.png\" alt=\"image\" width=\"630\" height=\"349\" border=\"0\" \/><\/a><\/p>\n<p>\u2026the duckling will think you are Momma, and from now on you\u2019ll have admin access to BlobShare.<\/p>\n<p>How did this happen? Didn\u2019t I say above that one user needs to be in the database in order to have access? Yes I did, but AccountAssociationClaimsAuthenticatonManager makes an exception for the case in which the database has exactly zero users. It even creates a new user for the occasion!\u00a0 The secret verification takes place in the associated controller (point (A ) in the uber-diagram).<\/p>\n<h1>Uploading Files<\/h1>\n<p>Now that we are admin, we can start to play. Let\u2019s sign in.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb5.png\" alt=\"image\" width=\"631\" height=\"436\" border=\"0\" \/><\/a><\/p>\n<p>..and we\u2019re in (BTW: wow, this sample looks great. The designers did an excellent job).<br \/>\nYou might not see anything out of the ordinary, but that\u2019s mostly because you didn\u2019t see that I used Live ID for signing in. Live ID does not give any claims besides the nameidentifier, whereas in the screenshot below BlobShare is clearly greeting me with something else (my email).<\/p>\n<p>That\u2019s because AccountAssociationClaimsAuthenticatonManager graciously recognized me as an existing user of BlobShare, hence retrieved my extra attributes (Name and email, which in this case are both set to the email value) and used them to augment the claims already in the existing ClaimsPrincipal.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image6.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb6.png\" alt=\"image\" width=\"632\" height=\"440\" border=\"0\" \/><\/a><\/p>\n<p>Let\u2019s go under Blobs.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image7.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb7.png\" alt=\"image\" width=\"621\" height=\"343\" border=\"0\" \/><\/a><\/p>\n<p>Hmm, it\u2019s pretty barren here. Let\u2019s click on Upload, then Single File Upload.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image8.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb8.png\" alt=\"image\" width=\"621\" height=\"418\" border=\"0\" \/><\/a><\/p>\n<p>Let\u2019s add a picture I am sure I own the rights for, and jolt down some comments just for color.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image9.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb9.png\" alt=\"image\" width=\"622\" height=\"419\" border=\"0\" \/><\/a><\/p>\n<p>\u2026and here there\u2019s our first blob.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image10.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb10.png\" alt=\"image\" width=\"623\" height=\"420\" border=\"0\" \/><\/a><\/p>\n<p>Let\u2019s hit on Permissions.<\/p>\n<h1>Handling Access Rights and Users<\/h1>\n<p>Here I can grant access to this blob for users or roles, but I have none for now (apart from myself and the admin role, who already does have access).<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image11.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb11.png\" alt=\"image\" width=\"622\" height=\"419\" border=\"0\" \/><\/a><\/p>\n<p>Let\u2019s add a new role, then. Click on Roles on the top bar.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image12.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb12.png\" alt=\"image\" width=\"621\" height=\"418\" border=\"0\" \/><\/a><\/p>\n<p>Click new, and you get to the simplest role creation form you\u2019ve seen to date. Once you\u2019re done hit Update.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image13.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb13.png\" alt=\"image\" width=\"620\" height=\"418\" border=\"0\" \/><\/a><\/p>\n<p>Excellent, we have a role now; but no user to assign this to. Let\u2019s go to Users by clicking the associated entry in the top bar.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image14.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb14.png\" alt=\"image\" width=\"620\" height=\"417\" border=\"0\" \/><\/a><\/p>\n<h1>Inviting Users<\/h1>\n<p>Here there\u2019s the list of our users, currently including only myself. I could add many at once, but for the sake of demonstration I\u2019ll create just one. Hit on Invite User.<\/p>\n<p>(note: all those controllers, which require administrative privileges, are decorated by a custom AuthorizeAttribute which enforces things accordingly).<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image15.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb15.png\" alt=\"image\" width=\"620\" height=\"418\" border=\"0\" \/><\/a><\/p>\n<p>The matter is pretty simple: you specify an email address to send the invite to, and you decide which roles the new guy will belong to. Hit Create and you\u2019re done for now.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image16.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb16.png\" alt=\"image\" width=\"617\" height=\"413\" border=\"0\" \/><\/a><\/p>\n<p>The user has been created in BlobShare\u2019s database, and an email with the invitation has been sent; however until Adam has not accepted, we don\u2019t know which nameidentifier should be associated to this profile (nor from which identity provider we should expect Adam to come from).<\/p>\n<p>What happened is that BlobShare created a unique ID associated to this profile. That ID will be embedded in one registration URL that Adam will receive in the invitation; whomever will present a token through that URL will become Adam as far as BlobShare is concerned.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image17.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb17.png\" alt=\"image\" width=\"615\" height=\"413\" border=\"0\" \/><\/a><\/p>\n<h1>Accepting an Invitation<\/h1>\n<p>Let\u2019s take a look at things from Adam\u2019s perspective.<\/p>\n<p>Adam receives the invitation mail below. The mail contains the mentioned invitation URL; nobody but Adam (or better, whomever has access to the mailbox specified at invitation time) know this URL, which is a pretty good way to be reassured that we are inviting the right person. Let\u2019s click on the URL.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image18.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb18.png\" alt=\"image\" width=\"616\" height=\"395\" border=\"0\" \/><\/a><\/p>\n<p>Here we once again encounter the sign-in page (again, at the time it was supposed to say sign-up and some helpful text, but that\u2019s a technicality). Adam can use whatever account from the listed providers: that account will become Adam for BlobShare. Once again, take a look at AccountAssociationClaimsAuthenticationManager\u00a0 to see how the reconciliation happens.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image19.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb19.png\" alt=\"image\" width=\"612\" height=\"283\" border=\"0\" \/><\/a><\/p>\n<p>Once the profile-token reconciliation took place, you can even update some values (like the name that was originally specified when creating the invitation).<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image20.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb20.png\" alt=\"image\" width=\"608\" height=\"321\" border=\"0\" \/><\/a><\/p>\n<p>Once signed in (again) and gone to Blob, Adam will find that there are still no blobs he can see. Let\u2019s leave Adam for a moment and go back to the administrator\u2019s experience.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image21.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb21.png\" alt=\"image\" width=\"607\" height=\"328\" border=\"0\" \/><\/a><\/p>\n<h1>Assigning Roles &amp; Permissions<\/h1>\n<p>If you refresh Adam\u2019s page, you\u2019ll see that the user is now active and the attributes all have the correct values.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image22.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb22.png\" alt=\"image\" width=\"606\" height=\"502\" border=\"0\" \/><\/a><\/p>\n<p>Now that our Colleagues role is non-empty, we can get back there and assign some permissions.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image23.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb23.png\" alt=\"image\" width=\"606\" height=\"379\" border=\"0\" \/><\/a><\/p>\n<p>And here it is: the Colleagues role has been granted Read access to our only blob. Note that I could have granted access directly to Adam instead of the group he belongs to; or that I could have put my blob in a blob set and handled access to the set rather than the individual blob. BlobShare is VERY flexible.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image24.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb24.png\" alt=\"image\" width=\"606\" height=\"400\" border=\"0\" \/><\/a><\/p>\n<p>It is worth stressing that all those changes are happening in the SQL Azure database, not in ACS: no new rules are being written. In BlobShare all settings are at the RP side.<\/p>\n<h1>Accessing a File<\/h1>\n<p>Let\u2019s get back to Adam. If Adam hits F5, the browser will refresh &amp; show the newly granted blob.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image25.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb25.png\" alt=\"image\" width=\"607\" height=\"304\" border=\"0\" \/><\/a><\/p>\n<p>Adam can hit both the name of the file in the blob (Phoenix in the sample) or Download. Access-wise there is no difference, this only impacts how the file will be served. Clicking on the file will show it in the browser, as you can see below (yes, that was a LONG meeting).<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image26.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb26.png\" alt=\"image\" width=\"606\" height=\"606\" border=\"0\" \/><\/a><\/p>\n<p>Now, until now I omitted to mention the BlobAuthorizationManager. The reason is that the guy steps out of the way every time the request is going to a controller other than MyBlobs. If it is MyBlobs, as it is the case now, it queries the db (via a service) to ensure that the user has the rights to access the blob he is requesting. Check out the code, it\u2019s very nicely readable.<\/p>\n<h1>Reports<\/h1>\n<p>Let\u2019s get back to the administrator for one more thing. If you click on Reports, you\u2019ll land on the page below.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image27.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb27.png\" alt=\"image\" width=\"606\" height=\"307\" border=\"0\" \/><\/a><\/p>\n<p>Let\u2019s click on User Activity; we\u2019ll see all the things we\u2019ve been doing until now with BlobShare, which is quite handy. If you look at the code, you\u2019ll see that the current ClaimsIdentity is used across the board for retrieving the user info in a nice, consistent way, regardless of whether they come from the identity provider or they have been extracted from the RP database.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image28.png\"><img loading=\"lazy\" decoding=\"async\" style=\"background-image: none; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/image_thumb28.png\" alt=\"image\" width=\"608\" height=\"734\" border=\"0\" \/><\/a><\/p>\n<h1>Summary<\/h1>\n<p>Well, the afternoon kind of stretched well into the evening <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-style: none;\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/wlEmoticon-smile.png\" alt=\"Smile\" \/> but BlobShare is a great sample, and I think it deserves all the coverage it can get.<\/p>\n<p>If you are into WIF, this is a great sample that demonstrates how to take advantage of the main extensibility points. Do play with the code, and if you have questions or feedback I am sure that the Wade gang will be delighted to hear you out. If you want to chat about the identity side of things, I am happy to chat as well but I can\u2019t take feature requests, that\u2019s Wade\u2019s jurisdiction <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-winkingsmile\" style=\"border-style: none;\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2012\/01\/wlEmoticon-winkingsmile.png\" alt=\"Winking smile\" \/><\/p>\n<p>Happy <a href=\"http:\/\/blobshare.codeplex.com\/\">BlobSharing<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Weather is not that good this Sunday afternoon, and the wife warned me already yesterday that today she was going to catch up with the AI class; hence, I think I am going to break the blog-silence and spend some time describing BlobShare, a little jewel my DPE friends quietly released last week&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1297,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[1],"tags":[116,117,114,115,113],"class_list":["post-99","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-access-control-service","tag-acs","tag-wif","tag-windows-azure","tag-windows-identity-foundation"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/99","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=99"}],"version-history":[{"count":3,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/99\/revisions"}],"predecessor-version":[{"id":101,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/99\/revisions\/101"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/1297"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=99"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=99"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=99"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}