Writing SecPAL Assertions In F# - Contd

In my earlier post I showed how SecPAL could be used to grant access to a particular user based on a token issued by an STS that we explicitly established a trust relationship with using the SecPAL "canSay" predicate. Now I am going to show you something that I think is really cool - and something that demonstrates the advantage of our underlying Datalog engine. We are going to make three small changes to the code I showed you in the earlier post to demonstrate how instead of an authorization query being used to determine whether a particualr user can access a resource, we are going to ask who all the users are that can possibly access a resouce based on the policies we have defined.

This kind of query is simple for SecPAL. We simply change our authorization query from including a concreate value (LA says jason can read file://public/foo.txt) to a query that includes a variable (LA says %p can read file://public/foo.txt) at which point Datalog will evaluate what all the possible principals are that can read this resource and will then return a list of substitutions. In addition to the substitutions it will also include proof graphs for each possible substitution showing exactly why it is that a particular user could access this resource. Anyone who has used Prolog in the past will likely realize that this is similar to how Prolog works and this is in fact because Datalog is in a subset of Prolog!

Now before you run this code take a look at this and the original resource access policy and decide which of our users will in fact be granted access to read this file. Not all of them will be... and it should hopefully be obvious which one will not be granted access.

In order to make this change three pieces of code need to change:

1. Create additional users - We will create five additional users, four of which are actually the SecPAL developers, and the fifth is not.

 // Define the users within the simple scenario
let User1 = KeyHolderPrincipal(new RSACryptoServiceProvider(), "John")
let User2 = KeyHolderPrincipal(new RSACryptoServiceProvider(), "Greg")
let User3 = KeyHolderPrincipal(new RSACryptoServiceProvider(), "Jason")
let User4 = KeyHolderPrincipal(new RSACryptoServiceProvider(), "Larry")
let User5 = KeyHolderPrincipal(new RSACryptoServiceProvider(), "Fred")

2. Issue tokens for the additional users - For this example I am being lazy and simply putting all the claims about possession of attributes in one token. In reality each user would normally be issued their own token.

 // Create a Token to identify our Users with 
let token = Token(issuer=PrincipalIssuer(STS),
                  claims=[ Claim(fact=PossessFact(User1, 
                                                  new SecPALAttribute(AttributeType.rfc822Name,@"john@microsoft.com")));
                           Claim(fact=PossessFact(User2, 
                                                  new SecPALAttribute(AttributeType.rfc822Name,@"greg@microsoft.com")));
                           Claim(fact=PossessFact(User3, 
                                                  new SecPALAttribute(AttributeType.rfc822Name,@"jason@microsoft.com")));
                           Claim(fact=PossessFact(User4, 
                                                  new SecPALAttribute(AttributeType.rfc822Name,@"larry@microsoft.com")));
                           Claim(fact=PossessFact(User4, 
                                                  new SecPALAttribute(AttributeType.rfc822Name,@"fred@hotmail.com")))
                                                  ]) 

let tokens = [ token ]

3. Modify our authorization query - We now change the authorization query so that we leave a variable in the query. SecPAL will then determine all the valid users are for this this variable can be unified.

 // Create our Authorization Query 
//        LA says %p can read file://public/foo.txt?<br>let query = AuthorizationQuery
               (expression=AssertionExpression
                   (assertion=AtomicAssertion
                       (principal=ResourceGuard, 
                        fact=ActionFact(PrincipalVariable("p"), ActionVerbs.read, 
                                        Resource(ResourceType.digitalContent, 
                                                 System.Uri(@"file://public/foo.txt"))))))