solid / authorization-panel

Github repository for the Solid Authorization Panel
MIT License
19 stars 20 forks source link

Authorization Capabilities for Linked Data #160

Closed elf-pavlik closed 3 years ago

elf-pavlik commented 3 years ago

During the call today @dmitrizagidulin pointed out that ZCAP-LD could be used for authorization, while discussing the use case described in #157 .

I'd like to start clarifying where exactly ZCAP-LD would be used. Looking in latest version of Solid Application Interoperability spec, especially Access Grants and Access Recipts look like possible place where ZCAP-LD could come into play.

For example we could consider using ZCAP-LD for Access Recipts. In that case in scenario from #157 Omni would grant access to Acme and send them Capability with detail of that access. Than Acme could delegate further by issuing child capabilities based on the parent capability issued by Omni. This actually sounds even better than Omni setting rules since it gives Acme much better control of what access they delegate to which employees. Using ZCAP-LD caveat they could further restrict how much of their access they delegate to specific employees.

Thinking about this use case and how data discovery is taking shape in Application Interoperability Spec, I started coming to conclusion that for Alice to know about data she can access in Omni storage, thanks to her Acme membership, Acme would most likely need to forward their Access Receipt to Alice or create Access Receipt for Alice based on Access Receipt from Omni. ZCAP-LD capability chain might actually provide clean way of doing it.

bblfish commented 3 years ago

The ZCAP spec draft points to Linked Data Capabilities as the place to go to get an overview of what it is about. So I went there first and read a good portion of it.

Saying-that logic

I really like that at least with this proposal the capabilities have understandable semantics, written in JSON-LD. So one can actually start reasoning about these.

(Side note: on the whole I am quite skeptical about the claims made by the capability proponents being applicable to Open Systems such as the Web. All the research I have found on Capabilities is put in terms of Operating Systems, which are closed systems, and where it is reasonable to have one service that knows all the data on the OS)

I think we can bring this type of work together with Linked Data and security by using the Abadi Needham Burrows Logic of Authentication. One of the early papers from 1991 Authentication in Distributed Systems: theory and practice started exploring the "speaks for" modality. This was developed over 20 years, with more recent papers such as Access Control in a Core Calculus of Dependency tying it in an interesting way into an important notion from Functional Programming, that of Indexed Strong Monad. Among the many advantages of having a logic for access control, this one from the 2009 paper Logic in Access Control (Tutorial Notes) stands out:

Attractively, says abstracts from the details of authentication. When p says s,p may transmit s in a variety of ways: – on a local channel via a trusted operating system within a computer, – on a physically secure channel between two machines, – on a channel secured with shared-key cryptography, or – in a certificate with a public-key digital signature.

What Abadi's work shows is that the core concept is that of a says relation between a Principal and a proposition. In RDF a proposition is an RDF Graph, and in N3 we can relate a Principal and a graph via a says relation.

In Linked Data we can have

:alice :says  <pubKeyDoc> .

If <pubKeyDoc> is fetched, we then have

:alice :says { 
   pkd:key 
       :owner :alice;
       :publicKeyPem """-----BEGIN PUBLIC KEY-----
..."""^^xsd:string .
}

So we should be able to formalize the paper by @cwebber and @harlantwood in terms of the says relation. In any case attempting to do this would be a very helpful thing to do.

Note: In RDF we don't usually link via a :says relation from an agent to the document, but link directly to the object inside the document, as :alice :key <pubKeyDoc#key> . There should be an easy translation between the two.

Using decentralised identifiers did's will have some advantage with respect to https: based link relations at the cost of extra protocol complexity. (we should list the advantages of dids so that we know at what point they will become necessary). But the good news is that if we can express both using the same logic, then we can start with https:// based claims, use signatures on dereferenced documents with linked data signatures when needed, and extend it into did's when the use cases for them make them necessary (presumably when one wants the key to be publicly available and immutable). The Linked Data Capabilities document actually is quite open to this too as I read it.

It should thus be no surprise that what can be expressed solely in terms of signed credentials can also be expressed in terms of linked data. We thus see that the delegation example in Linked Data Capabilities can also be modeled in terms of dereferenced linked data, as shown in the 2012 paper Extending the WebID Protocol with Access Delegation (this would need to be adapted of course).

Adapting this to Solid

Let us now consider how this ties in with Solid ACLs.

Link relation

First one key aspect of the Solid ACLs is that it correctly establishes that each resource is authoritative for what access control rules apply to it. This follows from the same logic of saying-that discussed above: doing a GET on a resource is a type of speech-act (see second chapter of my 2nd year report) restricted it is true to documents, so I call it a document-act. The web server serving the document is the authority over who can access it, so it is the right place to look for what the rights for that resource is. But on the web anything can link to anything, so user agents can land on a page by following links from anywhere. Having the resource itself specifies the groups of agents who are allowed access, is therefore the most efficient. This is what the Link: <doc.acl>; rel="acl" header is for.

ACLs, ACPs or just simply WAC?

The Linked Data Capabilities document rightly points out that the current access control system of Solid is ACL based. But that is just a pragmatic initial choice to enable Solid to gain experience with implementations, as ACLs are just the easiest to implement. But the acl framework is not limited to access control lists. It can easily be extended to describing agents by attribute, see the work on RelBAC.

An enhanced access control list, call it an access control policy, linked to from the resource could thus state that agents that can prove they are over 21 can access a given page. We can express age limitations as show in this example which could well be published by the International Standards Organization (ISO),

<#PersonOver21> owl:equivalentClass [  a owl:Restriction;
      owl:onProperty :hasAge ;
      owl:someValuesFrom   
          [ rdf:type   rdfs:Datatype ;
            owl:onDatatype       xsd:integer ;
            owl:withRestrictions (  [ xsd:minExclusive     21 ]   [ xsd:maxInclusive    150 ] )
          ]
       ] .

and we can express that all adult content can be viewed by people over 21

<#adultPermission> 
          :accessToClass :AdultContent;
          :agentClass iso:PersonOver21 ;
          :mode :Read .

These permissions don't need to be signed, since they are linked to from the authoritative resource and retrieved over the secure https (which involves cryptography of course).

Authentication

How would someone prove they are over 21? Here we can adapt the HTTP Signature based WebID Authentication to one linking to a Credential.

We can start with this very simple sequence diagram, which would require only the signature by the client of the HTTP headers, and then the rest can be done using https security.

Client                                Resource              KeyId           Age
App                                   Server                Doc             Credential
|                                        |                    |                |
|-request URL -------------------------->|                    |                |
|<---------- 401 + WWW-Auth Sig header---|                    |                |
|                                        |                    |                |
|--add Cred hdr+sign+keyId-------------->|                    |                |
|                           initial auth |                    |                |
|                           verification |                    |                |
|                                        |                    |                |
|                                        |--GET keyId-------->|                |
|                                        |<-------- keyId doc-|                |
|                                        |                                     |
|                             verify sig |                                     |
|                                        |                                     |
|                                        |--GET credential-------------------->|
|                                        |<-------------------send credential--|
|                                        |
|                       WAC verification |
|                                        |
|<----------------------send content-----|

Here the client would sign the http headers as per Signing HTTP Messages draft spec, passing in an extra signed header, such as Credential: <https://ageservice.co.uk/creds/1231231>. The referred to document would just need to make the statement that the agent with the given key is over 21.

This of course assumes the server has a way to tell if https://ageservice.co.uk is a legitimate age verification service. That will need to be done in an ad-hoc manner at least until we get a Web of Nations.

Here we get to see the power of the "says-that" logic.

I think that example shows how one can move fluidly between a simple https dereferencing service and a signature based one. The advantage of simple https based services is that everyone knows how they work, so people can get going developing those using very well established tools. We know though that as other requirements come in (perhaps people don't want the age verification service to know what services they are using), then signed credentials can take over.

Capabilities

Capabilities can be added to the above simply by having Credentials where one agent states that another agent can do certain actions on certain resources. That is it looks like Capabilities are nested saying-that relations. That is Alice who has access to a certain set of resources may give a Credential Capability to Bob to access a resource. This would be a statement of the form "Alice says { bob read ImagesOnServer }". Bob could then connect using the above protocol but linking to the Credential Capability instead.

elf-pavlik commented 3 years ago

I have been just watching video: Tristan Slominski – Delegation: the missing piece of authorization, those three slides seem to confirm that Access Grants in Application Interoperability Spec are closer to Capabilities than Access Control Lists

image

image

image

@justinwb I think it would be really helpful to present current state of art on Access Grants and Access Recipes on next Authorization Panel meeting.

bblfish commented 3 years ago

The example in the video posted by @elf-pavlik on Delegation is interesting. There are three actors:

  1. The Bank
  2. The user (call her Alice)
  3. Intuit Mint

Alice wants to give Read access to her bank account history to Mint, so that Mint can use this to information to give Alice an overview of her financial situation. This would be easy to do with Solid.

To get this to work, we don't even here need anything more than a slightly extended version of the current WAC ontology, using some ideas put forward by @emmettownsend's ACP. All Alice would need to do is edit a policy at <https://bank.com/alice/P4Mint> that gives Mint access to the account history collection and apply that to the collection. This has the immediate advantage that removing access to Mint is as simple as removing Mint's WebID from that policy. It is really not clear here what delegation achieves, other than adding a whole lot of complexity, making it difficult to track who did what, and creating problems for revocation. Indeed the whole talk is about an attempt to find a way to enable revocation, by going through a Proxy, called a Membrane.

If the idea is that the user does not want the bank to know that Mint is accessing the collection, the data could just be copied to the users pod and the data there be given access to Mint. And if we go further in the Solid philosophy, there is actually no need to give Mint.intuit access to the data at all. Mint could write a hyper app and that hyperapp could analyze the data on the user's pod without having to transfer data at all.

How would we get this to work with capabilities, if we found a better example where it made sense? Well, let's just apply ZCap-LD in a simple way. Alice just needs to take the policy </alice/P4Mint> now signed by the bank and send it on to Mint as shown in the slide below taken from the talk (see minute 19).

Screen Shot 2021-01-22 at 20 59 33

Mint could present the policy signed by the bank when accessing the resource, authenticate with a Mint key using the protocol shown in my previous post, and access the history collection in read only mode. What have we gained? Not that much really in this example. We have just slowed down the request by passing the policy along with it, and we have potentially created a revocation problem.

Let us say Alice does not want to go to create the policy file in the first place. She could then sign the RDF used for the policy herself and give it to Mint. The bank would then see that Alice had signed it, that she has the rights to the account history and see that the rights for Mint are restricted to reading. This is passing semantically rich capability files along as shown in the slide from the talk above. Again passing the certificate along in the request is a bit heavy, and creates a revocation problem.

But of course nobody is passing certificates around in the request, as we learn at minute 28 in the presentation in the demo with Amazon Web Services. Instead what is passed around is a capability URL, which consists of a domain of a server and an opaque token. But that token is really just a pointer for the bank to some document semantically equivalent to the Policy file we mentioned above. It could equally well be an https URL to the policy file. This is the so called "magic" of tokens: they are disguised URLs pointing at Policies, so that instead of having to pass policy around one just points to them. But that is what the authentication protocol I described above does too.

What we see here is exactly what follows from Abadi's logic of authentication, where he write in the 2009 paper Logic in Access Control (Tutorial Notes) that:

Attractively, says abstracts from the details of authentication. When p says s,p may transmit s in a variety of ways: – on a local channel via a trusted operating system within a computer, – on a physically secure channel between two machines, – on a channel secured with shared-key cryptography, or – in a certificate with a public-key digital signature.

He could have added that instead of passing s, the p could just pass a URL for s, call it S, where S points to the content s. Ie instead of p says s we have p says S. (which works as long as the S url is secure)

There is really no difference in the logic of "saying that" to a document being signed or it being fetched. Both can be done, both have their uses: they fall within the same logic. The main thing the bank needs to know is what Principal said what, and if they are entitled according to the bank to say that.

elf-pavlik commented 3 years ago

All Alice would need to do is edit a policy at <https://bank.com/alice/P4Mint> that gives Mint access to the account history collection and apply that to the collection.

Thinking about variations of #157 Omni Corp. could grant read-write (not control) access to Acme Corp. for project A, B and C. Now Acme wants to delegate read-write access for Project A to team X and read-write access to Project B to team Y. With capabilities it seems straight forward. Acme could independently from Omni create child capability for team X and another child capability for team Y, with caveat of only project A and project B respectively. WAC or ACP doesn't seem to provide such flexibility since Omni Corp. wouldn't give Acme Corp acl:Control access (WAC) or write access to ACR (ACP).

In similar way capabilities may gracefully solve requirement for 2.5.2. Limiting application access while not acting as resource controller. Where Alice would create child capability for PerformChart with read-only caveat.

emmettownsend commented 3 years ago

Hi

In ACP you would just give append access to the relevant Rule for the relevant policy. The rule would need to be an external resource rather than directly contained in the ACR.

Cheers

Emmet

On Friday, 22 January 2021, elf Pavlik notifications@github.com wrote:

All Alice would need to do is edit a policy at < https://bank.com/alice/P4Mint> that gives Mint access to the account history collection and apply that to the collection.

Thinking about variations of #157 https://github.com/solid/authorization-panel/pull/157 Omni Corp. could grant read-write (not control) access to Acme Corp. For project A, B and C. Now Acme wants to delegate read-write access for Project A to team X and read-write access to Project B to team Y. With capabilities it seems straight forward, they Acme could independently from Omni create child capability for team X and another child capability for team Y, with caveat of only project A and project B respectively. WAC or ACP doesn't seem to provide such flexibility since Omni Corp. wouldn't give Acme Corp acl:Control access (WAC) or write access to ACR (ACP).

In similar way capabilities may gracefully solve requirement for 2.5.2. Limiting application access while not acting as resource controller https://solid.github.io/authorization-panel/wac-ucr/#uc-client-constraints. Where Alice would create child capability for PerformChart with read-only caveat.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/solid/authorization-panel/issues/160#issuecomment-765727340, or unsubscribe https://github.com/notifications/unsubscribe-auth/AN5EYKJGQQHUIHSQLCQ3SL3S3H5NVANCNFSM4WL24LVA .

-- Emmet Townsend, VP Engineering Contact | +44.759.023.8177 (M) Connect | LinkedIn https://www.linkedin.com/in/emmettownsend, WebID https://emmettownsend.inrupt.net/profile/card#me, Twitter https://twitter.com/emmettownsend Explore | www.inrupt.com

-- This e-mail, and any attachments thereto, is intended only for use by the addressee(s) named herein and may contain legally privileged, confidential and/or proprietary information. If you are not the intended recipient of this e-mail (or the person responsible for delivering this document to the intended recipient), please do not disseminate, distribute, print or copy this e-mail, or any attachment thereto. If you have received this e-mail in error, please respond to the individual sending the message, and permanently delete the email.

elf-pavlik commented 3 years ago

Hi @emmettownsend,

In ACP you would just give append access to the relevant Rule for the relevant policy.

This sounds like an approach to adding an agent to which the policy would apply but how one would remove that agent later on if needed?

The rule would need to be an external resource rather than directly contained in the ACR.

Would that require agent needing to modify a relevant Rule to have read access to the ACR? This way they would be able to find relevant rules, where they would have different access to different rules. Or do you see agent getting reference (IRI) to a rule, which they can modify, through some notification at the time when access to that rule was granted to them? I think they still would need to be able to have read access to the that relevant policy.

Could you imagine writing some snippets for those two use cases:

bblfish commented 3 years ago

@elf-pavlik wrote:

Thinking about variations of #157, Omni Corp. could grant read/write (not control) access to Acme Corp. for project A, B and C. Now Acme wants to delegate read/write access for Project A to team X and read/write access to Project B to team Y.

These restrictions are starting to make more sense of your Acme use case. Without them it sounds like Omni is giving access to the entirety of its web site to Acme Corp, suggesting a takeover had just happened.

So let us imagine that Omni has a set col of ldp:Collections

val col = Set("A","B","C").map("https://omni.com/proj/"+_+"/") 

Omni wants to allow employees of Acme to have read/write access to elements of col . Let us imagine that Acme is a small consulting company of 64 people with 8 teams.

With capabilities it seems straight forward. Acme could independently from Omni create child capability for team X and another child capability for team Y, with caveat of only project A and project B respectively. WAC or ACP doesn't seem to provide such flexibility since Omni Corp. wouldn't give Acme Corp acl:Control access (WAC) or write access to ACR (ACP).

For this to work, Omni's Solid web server needs to know that this capability is enabled. It needs to know in Abadi's terms, that for the collection col acme can set the rules. So we have something like

∀ c ∊ col, ∀ r: IR .  r in <c>  → Acme controls may_access(p, r, Rd|Wr) 

which I read as: all information resources r that are in the collection referred to by any URI c in col are controlled by Acme. On p 150 of Abadi's Tutorial Abadi defines p controls s as an abbreviation for (p says s) → s.

This would allow Acme to give anyone access, even Omni's competitors. So Omni may feel more comfortable with a rule that restricts it to employees of Acme.

∀ c ∊ col, ∀ r: IR, ∀ p : Person .  
r in <c> ⋀ employs(Acme, p)  → Acme controls may_access(p, r, Rd|Wr) 

As we saw, Acme can "say" that some person has write access to a resource, by signing an RDF graph that states this. This can be done using the current ACL ontology using Linked Data Signatures with Acme's public key.

@prefix : <http://www.w3.org/ns/auth/acl#> .

<#a1> :accessTo <https://omni.com/proj/A/doc1>;
    :mode :Read; 
    :agent <https://acme.org/people/nick> .

This signed Credential could then be placed somewhere - on Acme's server would be a reasonable default but elsewhere would work too - and it could be referred to using the HTTP-Signature protocol I described in an earlier message. Assume Acme decides to publish the Capability on its server at <https://acme.org/cap/123>. Then the client could pass the URL for the capability to the omni server when authenticating.

Now of course it would be quite a lot of work for the administrator to create a capability for the product of each of its employees and each of the resources. So it is more efficient for the Acme administrator to give r/w access the contents of a collection to a team by signing a graph such as the following using Linked Data Signatures and placing it on its Solid server

@prefix : <http://www.w3.org/ns/auth/acl#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix ldp: <https://www.w3.org/ns/ldp#> .

<#a1> :accessToClass [ a owl:Restriction;
          owl:onProperty ldp:contains;
          owl:Value <https://omni.com/proj/A/> ];
    :mode :Read ; 
    :agentClass <https://acme.org/team/X> .

Note that the graph would not need to be signed if linked to directly from the LDP Container ACR. The Omni Guard would only accept such capabilities, if they fit the rule we stated above. This may require N3 reasoning. A rule like this could do

{ </proj/A/> ldp:contains ?r .
  acme:co :employs ?p } => { 
       acme:co :controls { 
          [] ldp:accessTo ?r ; 
             ldp:mode ldp:Write; 
             ldp:agent ?p .
       } 
   }
elf-pavlik commented 3 years ago

Now of course it would be quite a lot of work for the administrator to create a capability for the product of each of its employees and each of the resources. :agentClass <https://acme.org/team/X> .

I think we getting again scenario where The Omni Guard would need to be able to access https://acme.org/team/X.

Keeping in mind that first example in ZCAP-LD draft shows how revocation mechanism could work:


 // Alyssa adds a caveat: Ben can drive her car, unless she flips
 // the bit at this url
 "caveat": [
   {"type": "ValidWhileTrue",
    "uri": "https://social.example/alyssa/ben-can-still-drive"}],

I don't see issue with Acme capabilities service having https://acme.org/team/X only accessible to itself and based on that issue and revoke child capabilities for each member of the team.

Each team member can also use their capability to aid data discovery for applications they use, plus authorize those applications before they can even discover any of the data user has capabilities to access.

If we combine that variant of #157, which includes team Acme:X with read-write access to Omni:A and team Acme:Y with read-write access to Omni:B, with 2.5.2. Limiting application access while not acting as resource controller. We get situation that Alice working as member of Acme:X wants to further restrict PerformChart access to Omni:A as read only. I see it elegant to have Alice's capabilities service to issue child capability for PerformChart with read only caveat and mentioned revocation mechanism.

I would imagine following chain of capabilities, more chains would have the same parent:

(each issued by capability service of the party before -> )

Omni -> Acme | read-write to Omni:A, Omni:B, Omni:C Acme -> Alice (member of Acme:X) | read-write to Omni:A Alice -> PerformChart | read to Omni:A

Once Alice authorizes PerformChart using something like consent screen example in interop spec. Preferably PerformChart can use the capability as a bread crumb to discover existence of Omni:A which now Alice can access using PeformChart in read-only mode.

bblfish commented 3 years ago

@elf-pavlik wrote

I think we getting again scenario where The Omni Guard would need to be able to access https://acme.org/team/X.

I don't think that we are forced to require access to the team resource. But also, I don't see that this is going to be that problematic in most situations that satisfy your use case #157. If privacy is important, the team X could just be described by listing the public keys used by its members.

@prefix cert: <http://www.w3.org/ns/auth/cert#> .

<> rdfs:member 
       [ a foaf:Agent;
         cert:key [ cert:modulus "aed12.."^^xsd:hexBinary; cert:exponent 65537 ]
       ],
       [ a foaf:Agent;
          cert:key [ cert:modulus "de78.."^^xsd:hexBinary; cert:exponent 65537 ]
       ],
       ...

That information says so little, it could even be placed on a public blockchain. So you'd just need an agreed upon blockchain URL to refer to the public record and it would work too.

If you want group descriptions, or even individual descriptions, which are not accessed by reference, then you will need to pass the signed JSON-LD in the HTTP request. I am not sure if there is a way to do that, but if there is we can follow the same says logic.

Perhaps it can be accessible through the browser with existing technologies?

One interesting idea would be to think of every web browser having its mini web server, that the connected to server can do requests on, but where individual resources are accessible via relative URLs. Then there would be a session based reference, but not a global one.

emmettownsend commented 3 years ago

Hi @emmettownsend https://github.com/emmettownsend,

In ACP you would just give append access to the relevant Rule for the relevant policy.

This sounds like an approach to adding an agent to which the policy would apply but how one would remove that agent later on if needed?

This would require Write access rather than Append access. If we wanted to allow this agent to add and remove from the rule but not touch existing rule statements then we would have to create a new rule and give the agent write access. Then add this new rule to the policy.

The rule would need to be an external resource rather than directly contained in the ACR.

Would that require agent needing to modify a relevant Rule to have read access to the ACR? This way they would be able to find relevant rules, where they would have different access to different rules. Or do you see agent getting reference (IRI) to a rule, which they can modify, through some notification at the time when access to that rule was granted to them? I think they still would need to be able to have read access to the that relevant policy.

The agent could have read access to the ACR which would allow them to see the policies that are used. Remember the Policies could be in the ACR or externalised. If they are externalised then they would only be able to see the rules applied in the Policy if they have Read access to the external Policy.

Alternatively they could be given the IRI for the rule(s) and/or Policies they are allowed to change.

This is all really a function of the use case, the application that creates the policies and rules, and the permissions that are set on the ARC, Policies and Rules.

Could you imagine writing some snippets for those two use cases:

I'll have a look now.