Open bblfish opened 3 years ago
That is the range of
:mode
allows the class of Flying Saucers as range too.
rdf:rage
doesn't actually restrict or allow anything it just enables reasoner to infer that object of the statement also has certain class.
https://github.com/solid/web-access-control-spec#authorization-schema has clear way of restricting valid values using ShEx
cl:mode [acl:Read acl:Write acl:Control]+ ;
In WAC the ontology is the primary normative document we always worked from. The ShEx statements are restrictions added post-hoc that are not agreed upon and are clearly stated to be non-normative.
Furthermore, as shown in the discussion of :agentClass
in the wac-acp-diff PR we see how Shape expressions can easily be overly-restrictive and wrong. The acl:mode
ShEx may capture a certain usage, but cannot be used to restrict evolution of the ontology.
The ACL ontology allows new acl:Access
subclasses such as acl:Delete
or acl:Create
, and over time these have been proposed and argued for and against. The point is not to argue here that we should use those, just that the ontology clearly means that to be possible, but does not state it clearly enough.
rdf:range
doesn't actually restrict or allow anything it just enables reasoner to infer that object of the statement also has certain class.
Indeed, therdf:range
on acl:mode
should allow the reasoner to infer that the object of the statement is a subclass of acl:Authorization
but it does not. The proposed fix would allow that to be inferred.
https://github.com/solid/web-access-control-spec#authorization-schema has clear way of restricting valid values using ShEx
Cool. Nice try. Please read the whole section.. starting with the very first sentence:
This section is non-normative. ( Issue: https://github.com/solid/specification/issues/169 )
I've accepted the PR https://github.com/solid/web-access-control-spec/pull/77 from Eric (which you were also a participating in) conditionally.
Indeed, the
rdf:range
onacl:mode
should allow the reasoner to infer that the object of the statement is a subclass ofacl:Authorization
but it does not. The proposed fix would allow that to be inferred.
I don't see how that helps with case suggested by your previous statement:
That is the range of :mode allows the class of Flying Saucers as range too.
One could still use ex:FlyingSaurcers
as value. Maybe I misunderstood OWL reasoning but your restriction would just imply ex:FlyingSaurcers rdfs:subClassOf acl:Access
which technically seems fine as long as reasoner doesn't get statements like
[] rdf:type owl:AllDisjointClasses ;
owl:members ( acl:Access ex:FlyingSaurcers ) .
In other words I don't think it can address https://github.com/solid/specification/issues/169 while a Data Shape, ether ShEx or SHACL, does.
I don't have objections to having suggested OWL restriction added to the vocab. I just don't see where it would come useful.
While we are at it we could also fix acl:accessToClass
and acl:agentClass
in the same way. These are currently defined as:
acl:accessToClass a rdf:Property;
:comment "A class of information resources to which access is being granted.";
:domain acl:Authorization;
:label "to all in";
:range :Class .
acl:agentClass a rdf:Property;
:comment "A class of persons or social entities to being given the right";
:domain acl:Authorization;
:label "agent class";
:range :Class .
But it would be more correct for them to be:
acl:accessToClass rdf:range [ a owl:Restriction ;
owl:onProperty :subClassOf ;
owl:hasValue ldp:Resource
] .
acl:agentClass rdf:range [ a owl:Restriction ;
owl:onProperty :subClassOf ;
owl:hasValue foaf:Agent
] .
@elf-pavlik:
I don't have objections to having suggested OWL restriction added to the vocab.
Good.
I just don't see where it would come useful.
It allows us to think more clearly about modeling issues.
For example, in the case of acl:agentClass
the ontology allows usages such as that described in issue 176, allowing us to describe classes of agents by attribute such as age, possession of a credential, etc... Those are clearly allowed by the ontology but not by the proposed ShEx rules. This can lead to the false belief that the ACL ontology is limited in ways it is not. See for example the assumption that WAC is limited in ability to reuse policies.
In https://github.com/solid/authorization-panel/pull/178#discussion_r587447559
@bblfish: note: the acl Ontology would be a lot clearer if it restricted the range of acl:mode to the subclasses of acl:Access. See issue #187
And in initial comment here
@bblfish: That is the range of :mode allows the class of Flying Saucers as range too.
In on of later comments
@bblfish: Furthermore, as shown in the discussion of :agentClass in the wac-acp-diff PR we see how Shape expressions can easily be overly-restrictive and wrong.
I just want to make sure that we all are on the same page. Neither rdfs:range
or rdfs:domain
restrict or allow anything. It just implies something specific by providing grounds for reasoner to infer additional statements that were not explicitly asserted.
Even if we use class defined using owl:Restriction
for rdfs:range
or rdfs:domain
when defining a predicate it still doesn't serve as any form of restriction or allowance on valid values for object or subject respectively in statements using that predicate.
I don't think we can say that data shapes definitions are more restrictive and RDFS (range & domain) are less restrictive. The later have nothing to do with restricting valid values so we can't directly compare them.
@elf-pavlik
Neither rdfs:range or rdfs:domain restrict or allow anything. It just implies something specific by providing grounds for reasoner to infer additional statements that were not explicitly asserted.
I disagree that those do not restrict anything. Say we define the infinite set of numbers divisible by 3 using the following description in mathematical notation, assuming we could do the same in RDF
Tr = { x | x % 3 == 0 }
This set includes the numbers {0, 3, 6, 9, ... }. Now, with the current ontology I can state that
:x acl:mode :Tr .
from which we can infer that :Tr :subClassOf :Class
which is true, since it :Tr
is a set of numbers.
But what the proposed change would allow us to conclude is that
:Tr :subClassOf acl:Access.
which is false, since a set of numbers is not an access mode. Indeed there is no interpretation where we have a reasonable definition of acl:Access
where that is true.
So for people who value true statements, that means that the second option is out of bounds. As such it does restrict what it is possible to express truthfully.
This restriction is very helpful, even if it is not fully automatiseable: for one it helps make the intent of the ontology clearer. For example it makes it clear that acl:Delete
or acl:Create
would be quite reasonable things to have as the object of an acl:mode
statement. I believe those modes have been proposed recently for ACP we should be clear that the ACL ontology is compatible with such extensions. (But not with :Tr
as the object of :mode
- not everything goes).
The non-normative ShEx on the other hand state that
<#authShape> {
acl:mode [acl:Read acl:Write acl:Control]+ ;
}
which does restrict that objects of acl:mode
to only Read
, Write
and Control
.
So the ShEx here again over-constrain the way the ontology can be used.
Note: I am not to here taking a position on whether or not one should add new access modes.
I think it is fine to infer that :x
is an rdfs:subClassOf acl:Access
if :x
is the object in a statement where acl:mode
is the predicate.
That would be simply expressed by amending the ACL ontology statement acl:mode rdfs:range rdfs:Class
to acl:mode rdfs:range acl:Access
.
@bblfish I believe that your proposed change would actually mean that :x
as defined above would be infered as a rdfs:subclassOf
a blank node that happens to be an owl:Restriction
. So I don't think it is correct.
I think it is fine to infer that
:x
is anrdfs:subClassOf acl:Access
if:x
is the object in a statement whereacl:mode
is the predicate.
ok, great! That is the main thing I was hoping to get agreement on.
That would be simply expressed by amending the ACL ontology statement
acl:mode rdfs:range rdfs:Class
toacl:mode rdfs:range acl:Access
.
I had considered that but the problem I think is that the range of acl:mode
is not an instance of an acl:Access, but a subclass of acl:Access
. That is acl:Read is defined as
acl:Read a :Class;
:comment "The class of read operations";
:label "read"@en;
:subClassOf acl:Access .
So if you look at how foaf:knows is defined
foaf:knows a rdf:Property,
owl:ObjectProperty;
:domain foaf:Person;
:range foaf:Person.
Then you use it like this:
<#Jim> a foaf:Person.
:i foaf:knows <#Jim>.
Here the object of the above foaf:knows
instance <#jim>
is an instance of a Person, not a subclass of Person.
Subclass of foaf:Person
could be :Man
, :Woman
, :Child
, etc....
So what I was hoping to say with
acl:mode :range [ a owl:Restriction ;
owl:onProperty :subClassOf ;
owl:hasValue acl:Access
] .
is that the range of acl:mode
is anything that is a :subClassOf
the class acl:Access
.
@bblfish I believe that your proposed change would actually mean that
:x
as defined above would be infered as ardfs:subclassOf
a blank node that happens to be anowl:Restriction
. So I don't think it is correct.
I think I have it right, but I think it definitely needs careful checking. Looking at the primer with Turtle descriptions enabled (must be done manually).
The triple
P rdfs:range C
states thatP
is an instance of the classrdf:Property
, that C is an instance of the classrdfs:Class
and that the resources denoted by the objects of triples whose predicate isP
are instances of the classC
. -- https://www.w3.org/TR/rdf-schema/#ch_range
Therefore if you say :p rdfs:range :ParentClass
and :x :p :y
, you get the triple :x a :ParentClass
inferred.
A triple of the form:
C1 rdfs:subClassOf C2
states thatC1
is an instance ofrdfs:Class
,C2
is an instance ofrdfs:Class
andC1
is a subclass ofC2
. Therdfs:subClassOf
property is transitive. -- https://www.w3.org/TR/rdf-schema/#ch_subclassof
So similarly, if you say :ChildrenClass rdfs:subClassOf :ParentClass
and :x a :ChildrenClass
, you get the triple :x a :ParentClass
inferred.
I guess what you're talking about might be inferring :ChildrenClass rdfs:subClassOf :ParentClass
if :x :p :ChildrenClass
which I don't think is very doable (and not what would result from a blank node object in an rdfs:range
statement).
I don't see the text in the OWL 2 primer that suggests you can use blank nodes in the way you describe with rdfs:range
. Is it something you might quote or pinpoint?
The triple
P rdfs:range C
states thatP
is an instance of the classrdf:Property
, that C is an instance of the classrdfs:Class
and that the resources denoted by the objects of triples whose predicate isP
are instances of the classC
. -- https://www.w3.org/TR/rdf-schema/#ch_rangeTherefore if you say
:p rdfs:range :ParentClass
and:x :p :y
, you get the triple:x a :ParentClass
inferred.A triple of the form:
C1 rdfs:subClassOf C2
states thatC1
is an instance ofrdfs:Class
,C2
is an instance ofrdfs:Class
andC1
is a subclass ofC2
. Therdfs:subClassOf
property is transitive. -- https://www.w3.org/TR/rdf-schema/#ch_subclassofSo similarly, if you say
:ChildrenClass rdfs:subClassOf :ParentClass
and:x a :ChildrenClass
, you get the triple:x a :ParentClass
inferred.
yes. Agree with all the above.
What we want to specify is the range of :mode
, where it is used like this:
<#Rule> :mode :Read
:Read
is a subclass of acl:Access
, so the range of :mode
has to be sets of classes, not sets of individuals.
I guess what you're talking about might be inferring
:ChildrenClass rdfs:subClassOf :ParentClass
if:x :p :ChildrenClass
which I don't think is very doable (and not what would result from a blank node object in anrdfs:range
statement).I don't see the text in the OWL 2 primer that suggests you can use blank nodes in the way you describe with
rdfs:range
. Is it something you might quote or pinpoint?
Here is an example from the the OWL Primer
:Parent owl:equivalentClass [
rdf:type owl:Restriction ;
owl:onProperty :hasChild ;
owl:someValuesFrom :Person
] .
That is the class :Parent
is the set of all things that have a relation :hasChild
to some :Person
. That is an owl:Restriction
defines a class, via relations that objects have to other objects. It is denoted by a blank node, but that is for some complex logical reason I would need to study to understand fully. That is why one uses the owl:equivalentClass
relation there to name that class.
I could make it clearer by doing the same and name the class of access modes.
:ClassOfAccessModes owl:equivalentClass [ a owl:Restriction ;
owl:onProperty :subClassOf ;
owl:hasValue acl:Access
] .
acl:mode :range :ClassOfAccessModes .
:ClassOfAccessModes
is not a particularly good name, but I hope it gets the idea across.
The owl:equivalentClass
expressed as an owl:Restriction
over owl:someValuesFrom
is described as "existential quantification" which allows us to infer, for example, as per the OWL Primer that someone that is a parent has at least one child. So indicating a potentially untold/unknown statement.
The predicate you use in your owl:Restriction
axiom: "owl:hasValue
"; is meant to describe classes of individuals that are related to one particular individual via a predicate. In other words, by defining the owl:equivalentClass
of rdfs:subClassOf
acl:Access
, you are defining the class of subclasses of acl:Access
.
However:
...the subclass relationship between classes is transitive. Besides this, it is also reflexive, meaning that every class is its own subclass... -- https://www.w3.org/TR/2012/REC-owl2-primer-20121211/#Class_Hierarchies
An axiom EquivalentClasses( CE1 CE2 ) is equivalent to the following two axioms: SubClassOf( CE1 CE2 ) SubClassOf( CE2 CE1 ) -- https://www.w3.org/TR/owl2-syntax/#Equivalent_Classes
Maybe the most important bit is that the subclass relationship is reflexive and that every class is its own subclass. Therefore, the class of subclasses of acl:Access
is acl:Access
.
There is no need for an owl:equivalentClass
over an owl:Restriction
here.
I think what we want is: acl:mode rdfs:range acl:Access
.
you are defining the class of subclasses of acl:Access.
yes. This is expressed in functional programming as the difference between a function that has a range of A
and one that has as range Set[A]
ie Sets of A
s. In mathematics it is the difference between a range of A
and a range of the PowerSet of A, noted π«(A)
. Note that the sets of a Powerset are all ordered by subset inclusion β
which is transitive and reflexive, so that if A β B
and B β C
then A β C
. You can order the subsets of a Powerset by subset inclusion with the empty set at the bottom and the full set at the top. This forms a category.
It is a bit tricky to see how to model this in a type safe language like Scala.
But perhaps the following gives an idea. The idea is that Read
specifies a subclass of Access
and Work
a subclass of Agent.
trait AcessControlRule {
type Mode <: Access
type A <: Agent
def allow(agent: A, accessTo: Uri, mode: Mode): Boolean
}
trait Access {
def request(req: HttpRequest): Boolean
}
class Read extends Access {
def request(req: HttpRequest): Boolean = req.method == GET
}
class Write extends Access {
def request(req: HttpRequest): Boolean = req.method == PUT
}
object ReadAccessOnDocs {
type Mode = Read
type A = Work
def allow(agent: A, accessTo: Uri, mode: Mode): Boolean = accesstTo.path.startsWith("/docs/")
}
But of course it would not make sense to do this in a statically typed way. Instead on would have a function Access => Boolean
. Perhaps something like this:
val Read: Request => Boolean = (req: Request) => req.method == `GET`
But the set of functions A => Boolean
is the Powerset of A.
Let me try to ask a simple question: Are you trying to express that the range is all the subclasses of acl:Access
but not acl:Access
itself?
No, the range is the Powerset of acl:Access, ie. π«(Access)
not Access
. An element of π«(Access)
is a set like Read
, not an instance like an individual request event. On this reading, it would be ok to have
<#auth> :mode acl:Access.
which could be a way of expressing the authorization is enabled for "All modes of access".
This is ok because acl:Access β π«(acl:Access)
just like acl:Read β π«(acl:Access)
.
[@bblfish] This is ok because
acl:Access β π«(acl:Access)
just likeacl:Read β π«(acl:Access)
.
If I'm understanding the rest of this right, it seems that last should be acl:Read β π«(acl:Read)
, not acl:Read β π«(acl:Access)
...?
@TallTed it is also true that acl:Read β π«(acl:Read)
, but my point was to say that :ClassOfAccessModes
is really equivalent to π«(acl:Access)
, which is I think expressed by the following:
:ClassOfAccessModes owl:equivalentClass [ a owl:Restriction ;
owl:onProperty :subClassOf ;
owl:hasValue acl:Access
] .
The reason I come to this conclusion is that acl:Read
, acl:Write
and acl:Control
are all subclasses of acl:Access
in the ontology. So that would be compatible with the object ?obj
of a <#x> :mode ?obj
relation being any subclass of acl:Access
.
I see nothing relevant distinguishing :ClassOfAccessModes
from acl:Access
.
The only thing you gain is a couple of inferences that are probably not useful or welcome. To be clear, neither rdfs:range
nor owl:Restriction
s are actual restrictions, they are classifiers.
With acl:mode rdfs:range acl:Access
, if :x acl:mode :Y
, then :Y a acl:Access
.
With your axiom, if :Y rdfs:subClassOf acl:Access
AND :x acl:mode :Y
, then :Y a :ClassOfAccessModes
as well as :Y a _:BlankNodeOfTheRestrictionClass
. Besides, the first statement holding means that :Y a acl:Access
(since :Y
is a subclass of acl:Access
).
I don't see how that's an improvement and it is confusing.
the object
?obj
of a<#x> :mode ?obj
relation being any subclass ofacl:Access
.
Yes, absolutely. That is exactly what acl:mode rdfs:range acl:Access
expresses.
EDIT: And I mean, I get how the idea would be nice if it were an actual restriction. But I don't see how useful or fitting it is in this ontology/in order to draw classification inferences.
I see nothing relevant distinguishing :ClassOfAccessModes from acl:Access.
Do you see a difference between A
and π«(A)
?
It's the same difference.
Say you have the type Person
and the type π«(Person)
.
In the first case members of Person
are actual people like you and me. E.g. Henry: Person
In the second case we have groups of people, E.g. Adults: π«(Person)
.
Those are two different types.
With your axiom, if :Y rdfs:subClassOf acl:Access AND :x acl:mode :Y, then :Y a :ClassOfAccessModes as well as :Y a _:BlankNodeOfTheRestrictionClass. Besides, the first statement holding means that :Y a acl:Access (since :Y is a subclass of acl:Access).
(Let's ignore the blank node comment that a good reasoner will resolve)
What you are saying is that :Y rdfs:subClassOf acl:Access
implies :Y a acl:Access
.
But that is to confuse membership (written β) and inclusion (written β).
If we have a set of 3 Friends F = { Alice, Ben, Camille}
then Alice β F
but not {Alice, Ben}
β F, even if {Alice, Ben} β F
.
On the other hand {Alice, Ben} β π«(F)
.
That is because π«(F) = { {}, {Alice}, {Ben}, {Camille}, {Alice, Ben}, {Alice, Camille}, {Ben, Camille}, {Alice, Ben, Camille}}
These sets are related by inclusion as show in the diagram on the Powerset wikipedia page.
Do you see a difference between A and π«(A)?
Yes, and everything you say makes sense from a functional programming perspective.
What you are saying is that :Y rdfs:subClassOf acl:Access implies :Y a acl:Access. But that is to confuse membership (written β) and inclusion (written β).
It's not an implication or a confusion, it's basic inference. It's how RDF works.
RDF is not a strongly typed functional programming language and rdfs:range
is a simple classifier, not a restriction. All it does is help you infer some statements.
Can you translate with a few statements what you are trying to do in RDF?
We have currently a few Access Modes acl:Read
, acl:Write
, acl:Append
and acl:Control
they all happen to be of rdf:type acl:Access
and acl:Append
is also of rdf:type acl:Write
. We can also imagine having a future Access Mode x:Y
and when used in a statement of the form :x acl:mode x:Y
, then an inference engine would deduct that x:Y rdf:type acl:Access
.
What is your expected inferencing behaviour?
Do you see a difference between A and π«(A)?
Yes, and everything you say makes sense from a functional programming perspective.
What you are saying is that
:Y rdfs:subClassOf acl:Access
implies:Y a acl:Access
. But that is to confuse membership (written β) and inclusion (written β).It's not an implication or a confusion, it's basic inference. It's how RDF works.
Ok, so I think we need to go straight to the source here. Let's look at the inference rules from RDF 1.1 Semantics.
We have as rule 9, translated to N3 for readability the inference
{ ?xxx rdfs:subClassOf ?yyy .
?zzz rdf:type ?xxx . } => {?zzz rdf:type ?yyy}
This is different from the rule you are asserting which would be written
{ ?xxx rdfs:subClassOf ?yyy . } => {?xxx rdf:type ?yyy}
Rule 9, states that the instances of the subClass are instances of the superclass. ie that
x β y & z β x => z β y
This is not the same as stating that subclasses of the superclass are members of the superclass.
Henry, thank you for your patience. I have to say that you are right. I didn't think the distinction would hold, but it does.
Given a graph:
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <https://example.com/>
:mode rdfs:range :Access .
:x :mode :Read .
The following statements hold:
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <https://example.com/> .
:Access
a rdfs:Class, rdfs:Resource;
rdfs:subClassOf rdfs:Resource, :Access .
:Read
a rdfs:Resource, :Access . # The Read class is inferred to be of rdf:type :Access
:mode
a rdf:Property, rdfs:Resource;
rdfs:range :Access;
rdfs:subPropertyOf :mode .
:x
a rdfs:Resource;
:mode :Read .
Given a graph:
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix : <https://example.com/>
:mode rdfs:range [
a owl:Restriction ;
owl:onProperty rdfs:subClassOf ;
owl:hasValue :Access ;
] .
:x :mode :Read .
The following statements hold:
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix : <https://example.com/> .
_:node0
a rdfs:Class, rdfs:Resource, owl:Restriction;
rdfs:subClassOf _:node0, rdfs:Resource;
owl:hasValue :Access;
owl:onProperty rdfs:subClassOf .
:Access
a _:node0, rdfs:Class, rdfs:Resource;
rdfs:subClassOf rdfs:Resource, :Access .
:Read
a _:node0, rdfs:Class, rdfs:Resource; # The Read class is inferred to be of rdf:type _:node0 (not :Access)
rdfs:subClassOf rdfs:Resource, :Access, :Read . # The Read class is inferred to be rdfs:subClassOf :Access
:x
a rdfs:Resource;
:mode :Read .
The current ACL ontology has
The
:range
here is defined as any instance of rdfs:ClassThis is defined as
That is the range of
:mode
allows the class of Flying Saucers as range too. Clearly this should be restricted to the class of subclasses ofacl:Access
. which is defined asAnd indeed that is how Read, Write, Control, ... are defined.
One suggestion would be to fix this with
As described in the comment below the same reasoning applies to the range definitions of
acl:accessToClass
andacl:agentClass
.