-
Notifications
You must be signed in to change notification settings - Fork 2
Proposal for UML‐based agnostic Core model and XML JSON schema mapping rules
To support the discussion #38, here is a UML class diagram proposed as agnostic model for the Policy syntax, based on current XACML 4.0 draft schema and latest issues (Request/Response data models still need to be added to get a complete XACML model):
This class diagram relies on the new UML profile below for the definitions of the custom stereotypes (RestrictedString
, Meta
, etc.):
The choice of UML is mainly to have a graphical notation and a corresponding machine-readable data model that can be translated to XML schema and JSON schema as priority targets, but also schemas/grammars for other formats in the future as the need arises (YAML, CBOR...). Note that the JSON schema may be used for YAML as well to some extent.
To explore the UML diagrams in more details, you may import the projects in the ZIP file into Eclipse Papyrus (tested with v6.7.0 - 2024-06).
The next sections detail the mapping rules for mapping this UML model to the XML/JSON schemas (version Draft 2020-12 of JSON schema is used as reference):
Mapping rules for standard UML primitive types:
UML | XML schema | JSON schema |
---|---|---|
String | xs:string | string |
Boolean | xs:boolean | boolean |
Integer | xs:integer | integer |
A UML class Foo
stereotyped as <<RestrictedString>>
represents a subtype of String restricted by a regular expression R
, and this regex is specified as the pattern
property value. The regex delimiters ^$
are implicit in this case, i.e. this pattern is matched against the whole string. (like in XSD simpleType restriction's pattern
element).
If the class name is URI
(resp. NCName
), it is mapped to the standard xs:anyURI
(resp. xs:NCName
) type.
Else it is mapped to:
<xs:simpleType name="FooType">
<xs:restriction base="xs:string">
<xs:pattern value="R"/>
</xs:restriction>
</xs:simpleType>
This covers the following XML types used in XACML schema:
- xs:anyURI,
- xs:NCName,
- xacml:Version,
- xacml:VersionMatch.
If the class name is URI
, it is mapped to:
{ "type": "string", "format": "uri" }
Else it is mapped to a new subschema (regex delimiters ^$
must be explicit in the pattern expression):
"$defs": {
...
"Foo": { "type": "string", "pattern": "^R$" }
...
}
A UML class Foo
stereotyped as <<Enumeration>>
represents a subtype of String that is an enumeration of string literals X
, Y
, etc.
<xs:simpleType name="FooType">
<xs:restriction base="xs:string">
<xs:enumeration value="X"/>
<xs:enumeration value="Y"/>
...
</xs:restriction>
</xs:simpleType>
This covers the following XML type(s) used in XACML schema:
- xacml:Effect.
If there is at least one Datatype with a non-meta property (i.e. property not stereotyped Meta
) of type Foo
, then the definition above must be preceded by a definition of an element Foo
with type FooType
(non-meta properties will be references to this element) as follows:
<xs:element name="Foo" type="xacml:FooType"/>
<xs:simpleType name="FooType">
<xs:restriction base="xs:string">
<xs:enumeration value="X"/>
<xs:enumeration value="Y"/>
...
</xs:restriction>
</xs:simpleType>
This covers the following XML types / elements used in XACML schema:
- xacml:DecisionType / xacml:Decision.
"$defs": {
...
"Foo": { "enum": ["X", "Y", ...] }
...
}
A UML Datatype here is a class stereotyped as <<Datatype>>
, which represents a complex datatype as opposed to Primitive types described in the previous section, i.e. datatypes that can have properties.
Terms:
-
Abstract Datatype: Datatype whose
abstract
modifier is set totrue
and the title is italicized on the UML diagram. -
Empty Datatype: a datatype is said empty if it has no property in its definition, regardless of subtypes. E.g.
PolicyCombinedItem
,Expression
. -
Meta-property / non-meta property: a meta-property is a UML Datatype property stereotyped as
Meta
(marked<<Meta>>
in the UML diagram). Other properties are referred to as non-meta properties.
If an UML Datatype Foo
is an empty abstract Datatype used no more than once as property type in the whole data model (such as PolicyCombinedItem
), it is anonymized, i.e. not mapped to any corresponding XML type or element. It is only the (single) property of type Foo
of some other Datatype, if there is any, that is mapped to a xs:choice
of Foo
's subtypes, as explained in the Property mapping rules below. So Foo
is completely absent from the resulting XML schema.
Else (Foo
is not anonymized
):
-
Foo
is mapped to a globally definedxs:complexType
namedFooType
:<xs:complexType name="FooType">...</xs:complexType>
-
If
Foo
is stereotyped<<MixedContent>>
, this refers to XML Mixed Content (character data interspersed with child elements), i.e.mixed="true"
must be specified on thexs:complexType
:<xs:complexType name="FooType" mixed="true"> ... </xs:complexType>
This covers the following XML type(s) used in XACML schema:
- xacml:ContentType,
- xacml:AttributeValueType,
- xacml:AttributeAssignmentType.
N.B.: according to the table Complex Type Definition with complex content Schema Component of section 3.4.2 XML Representation of Complex Type Definitions of W3C XML schema specification, the
mixed
attribute oncomplexContent
is redudant if already defined on parentcomplexType
. -
If
Foo
is abstract, then the attributeabstract="true"
must be specified on the complexType:<xs:complexType name="FooType" abstract="true">...</xs:complexType>
This covers the following XML type(s) used in XACML schema:
- xacml:IdReferenceType,
- xacml:ExpressionType.
-
If
Foo
inherits from another Datatype - the supertype -Bar
(Generalization relationship) that is not anonymized either, then add the correspondingxs:complexContent
/xs:extension
to theFooType
complexType definition:<xs:complexType name="FooType"> <xs:complexContent> <xs:extension base="xacml:BarType"> ... </xs:extension> </xs:complexContent> </xs:complexType>
-
If there is at least one non-meta property of type
Foo
(and again,Foo
is not an anonymized Datatype as defined earlier), then thexs:complexType
definition must be preceded by a globally definedxs:element
namedFoo
with typeFooType
in XACML namespace (so that the other Datatype(s)' non-meta properties can make references to it as explained later in the Property mapping rules) as follows:<xs:element name="Foo" type="xacml:FooType"/> <xs:complexType name="FooType">...</xs:complexType>
-
Plus, if the UML Datatype is abstract (as defined earlier), this
xs:element
must also have the attributeabstract="true"
specified:<xs:element name="Foo" type="xacml:FooType" abstract="true"/> <xs:complexType name="FooType" abstract="true">...</xs:complexType>
This covers the following XML type(s) / element(s) used in XACML schema:
- xacml:ExpressionType / xacml:Expression.
-
Plus, if
Foo
inherits from a DatatypeBar
and a global element namedBar
is defined according to the mapping rule #5 above, then add thesubstitutionGroup="xacml:Bar"
attribute:<xs:element name="Foo" type="xacml:FooType" substitutionGroup="xacml:Bar"/> <xs:complexType name="FooType"> <xs:complexContent> <xs:extension base="xacml:BarType"> ... </xs:extension> </xs:complexContent> </xs:complexType>
N.B.: the
substitutionGroup
attribute can be multi-valued (so multi-inheritance is possible). -
Property mapping rules: for each property in the UML Datatype,
-
8.1. If the property is stereotyped as
<<Meta>>
(meta-property), convert to an XML attribute as follows:- The attribute name is the UML property name converted to Pascal case;
- The attribute type is the corresponding XML type according to the mapping rules defined in the previous UML Primitive Types section;
- If the property's multiplicity is
0..1
, specifyuse="optional"
, elseuse="required"
; - If the property has a default value, add the same
default
value to the attribute.
For example, a meta-property
myProperty
of typeBoolean
, multiplicity0..1
, default valuefalse
would translate to:<xs:attribute name="MyProperty" type="xs:boolean" use="optional" default="false"/>
A meta-property
myProperty
of typeEffect
, multiplicity1
(no default value) would translate to:<xs:attribute name="MyProperty" type="xacml:EffectType" use="required"/>
-
8.2. Else (the property is not stereotyped as
<<Meta>>
):-
8.2.1. If the property type - say
PropType
- is anonymized (cf. previous section), then map to an XML choice between the XML elements corresponding to allPropType
's subtypes. The property's multiplicity is mapped to thexs:choice
's minOccurs/maxOccurs similarly to the previous rules for meta-properties:- If the property's multiplicity is
0..1
, map tominOccurs="0"
(maxOccurs
is 1 by default); - If the multiplicity is
*
, map tominOccurs="0" maxOccurs="unbounded"
; - If the multiplicity is
1
, do not specify minOccurs/maxOccurs as 1 is the default value for both; - If the multiplicity is
1..*
, map tominOccurs="1" maxOccurs="unbounded"
.
For example, considering that the subtypes of the Datatype
PolicyCombinedItem
arePolicy
,PolicyReference
,VariableDefinition
andRule
, thePolicy
Datatype'scombinedItems
(non-meta) property with typePolicyCombinedItem
(abstract) and multiplicity*
will be mapped to:<xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xacml:Policy"/> <xs:element ref="xacml:PolicyReference"/> <xs:element ref="xacml:VariableDefinition"/> <xs:element ref="xacml:Rule"/> </xs:choice>
- If the property's multiplicity is
-
8.2.2. Else (the property type is not abstract or at least one other property in the data model have the same type) convert to an XML element refering to the element that has the same name as the property type, in the XACML namespace, and map the property's multiplicity to minOccurs/maxOccurs values as follows (same as above):
- If the property's multiplicity is
0..1
, map tominOccurs="0"
(maxOccurs
is 1 by default); - If the multiplicity is
*
, map tominOccurs="0" maxOccurs="unbounded"
; - If the multiplicity is
1
, do not specify minOccurs/maxOccurs as 1 is the default value for both; - If the multiplicity is
1..*
, map tominOccurs="1" maxOccurs="unbounded"
.
For example, a non-meta property
myProperty
of typeFoo
, multiplicity*
would translate to:<xs:element ref="xacml:Foo" minOccurs="0" maxOccurs="unbounded"/>
- If the property's multiplicity is
-
-
-
If
Foo
is stereotyped with<<AnyMetaProperty>>
, it allows to have any meta-property besides the meta properties explicitly defined in the class if there is any, which means any XML attribute may be added. This translates to axs:anyAttribute
element at the end of the list of XML attributes:<xs:complexType name="FooType" ...> ... <!-- Other attributes mapped from meta-properties of the UML class, if any. --> <xs:anyAttribute namespace="##any" processContents="lax"/> ... </xs:complexType>
This covers the following XML type(s) used in XACML schema:
- xacml:AttributeValueType.
-
If
Foo
is stereotyped with<<AnyProperty>>
, it allows to have any non-meta property besides the non-meta properties explicitly defined in the class if there is any, which means any child XML element may be added to the element sequence. This translates to axs:any
element at the end of the XML sequence; and its multiplicity (number of occurrences) depends on the value specified for theAnyProperty
stereotype'soneAndOnly
property:-
10.1. If
oneAndOnly="true"
(default value), this is equivalent to minOccurs = maxOccurs = 1 (one and only one) which may be omitted as these are the default values, so this translates to:<xs:complexType name="FooType" ...> ... <xs:sequence> <!-- Other elements mapped from non-meta properties of the UML class, if any. --> <xs:any namespace="##any" processContents="lax"/> </xs:sequence> ... </xs:complexType>
This covers the following XML type(s) used in XACML schema:
- xacml:ContentType.
-
10.2. If
oneAndOnly="false"
(zero or more), this is equivalent to minOccurs=0 and maxOccurs=unbounded:<xs:complexType name="FooType" ...> ... <xs:sequence> <!-- Other elements based on explicit properties of the UML class, if any. --> <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> ... </xs:complexType>
This covers the following XML type(s) used in XACML schema:
- xacml:AttributeValueType,
- xacml:StatusDetailType.
-
-
Apply mapping rules based on the JSON Profile: the JSON schema of certain UML Datatypes is defined by the JSON Profile of XACML 3.0 (the JSON Profile will need some update to align with new XACML 4.0 model):
-
Content: defined as JSON string according to the JSON profile, section 4.2.2, 4.2.3.
{"type": "string"}
-
AttributeValue (4.2.4):
"AttributeValue": { "description": "Security warning: this definition allows any JSON object as value. TODO: find a way to validate it somehow. Possible solutions: 1) Modify this schema in production to restrict possible values as much as possible. 2) Any equivalent of XML processContents='strict'. 3) Any JSON processor that enforces a max text length, max number of keys, max object depth.", "anyOf": [ { "type": "array", "items": { "type": "boolean" }, "minItems": 0 }, { "type": "array", "items": { "type": ["number"] }, "minItems": 0 }, { "type": "array", "items": { "type": ["string"] }, "minItems": 0 }, { "type": "array", "items": { "type": "object" }, "minItems": 0 } ] }
-
Attribute (4.2.4):
"Attribute": { "type": "object", "properties": { "AttributeId": { "type": "string", "format": "uri-reference" }, "Issuer": { "type": "string" }, "IncludeInResult": { "type": "boolean" }, "DataType": { "type": "string", "format": "uri-reference", "default": "http://www.w3.org/2001/XMLSchema#string" }, "Value": { "$ref": "#/defs/AttributeValue" } }, "required": [ "AttributeId", "Value" ], "additionalProperties": false }
N.B.: according to the resolution of issue #18, the Attribute with IncludeInResult is renamed to RequestAttribute, whereas the Attribute in Result and PolicyIssuer does not have IncludeInResult anymore.
-
To be defined: Request, Response, Result, Status, MissingAttributeDetail, StatusCode, AttributeAssignment.
Note: all
MixedContent
Datatypes (Content, AttributeValue, AttributeAssignment ) are already addressed in Special cases above. -
-
Else (the UML Datatype is not in the previous list):
-
1.1. If the UML Datatype is stereotyped
<<MixedContent>>
, raise an error Unsupported as no other MixedContent datatype is allowed besides the Content, AttributeValue and AttributeAssignment in the previous list. -
1.2. Else (not MixedContent), skip to the next rule.
-
-
If the UML Datatype
Foo
is abstract,-
3.1. If
Foo
is empty (no property) (e.g.Expression
,PolicyCombinedItem
), map to aoneOf
composition of the schema references to all ofFoo
's subtypes' subschemas, including indirect subtypes', which implies that each subtype ofFoo
must have one:"$defs": { ... "Foo": { "oneOf": [ { "$ref": "#/$defs/Subtype1" }, { "$ref": "#/$defs/Subtype2" }, ... ] } ... }
For example, the
Expression
Datatype is mapped to:"$defs": { ... "Expression": { "oneOf": [ { "$ref": "#/$defs/AttributeValue" }, { "$ref": "#/$defs/AttributeDesignator" }, { "$ref": "#/$defs/Function" }, { "$ref": "#/$defs/Apply" } ... ] } ... }
-
3.2. Else (
Foo
is not empty, e.g.IdReference
Datatype),Foo
is mapped to the following (the subtypes will useFooBase
type as actual subtype in the JSON schema as shown in the next mapping rules):"$defs": { ... "FooBase": { "type": "object", "properties": { ...the properties... }, "required": [...properties with multiplicity 1 or more...], "additionalProperties": false }, "Foo": { "oneOf": [ { "$ref": "#/$defs/Subtype1" }, { "$ref": "#/$defs/Subtype2" }, ... ] } ... }
-
-
Else (
Foo
is not abstract):- 4.1. If it does not inherit from another Datatype or inherits from an empty (abstract or not) Datatype, then map to a JSON object type as follows (the empty supertype is ignored, and
"additionalProperties": false
by default):"$defs": { ... "Foo": { "type": "object", "properties": { ...the properties... }, "required": [...properties with multiplicity 1 or more...] "additionalProperties": false } ... }
- 4.2. Else (
Foo
inherits a non-empty DatatypeBar
):-
4.2.1. If the (non-empty) supertype
Bar
is abstract, considering a newBarBase
type has been defined according to previous rule 3.2, then mapFoo
to the following schema:"$defs": { ... "Foo": { "allOf": [ { "$ref": "#/$defs/BarBase" }, { "type": "object", "properties": { ...the properties... } "required": [...] "additionalProperties": false } ] } ... }
-
4.2.2. Else (
Bar
supertype is not abstract), then useBar
(instead ofBarBase
) as base type:"$defs": { ... "Foo": { "allOf": [ { "$ref": "#/$defs/Bar" }, { "type": "object", "properties": { ...the properties... } "required": [...] "additionalProperties": false } ] } ... }
-
- 4.1. If it does not inherit from another Datatype or inherits from an empty (abstract or not) Datatype, then map to a JSON object type as follows (the empty supertype is ignored, and
-
Property mapping rules: for each property in the UML Datatype,
- 5.1. The Property is mapped to a JSON property in the JSON object type definition as follows:
-
The JSON property name is the same as the UML property name.
[!NOTE]
Should we use Pascal case like the XACML/XML schema instead? Isn't this awkward for JSON?[!WARNING]
This is not strictly equivalent to the UML model since theMeta
stereotype is ignored (no difference between meta and non-meta properties in JSON). -
The UML property type
Foo
is mapped to a JSON subschema or a reference to one, as follows:- If
Foo
is one of the UML Primitive Types that can be mapped to a JSON standard type/format (see UML Primitive Types section), e.g.string
/uri
for UMLURI
type, then ("format" is optional) use a subschema:
{ "type": "matching_standard_json_datatype", "format": "matching_standard_format_if_necessary" }
Else there must be a corresponding subschema
Foo
as defined by previous rules, in which case you use a subschema reference instead:{ "$ref": "#/$defs/Foo" }
- If
-
- 5.2. The property's multiplicity is mapped as follows:
-
0..1
: do not include the property name in therequired
array of the subschema definition;e.g. for two UML properties, one of which does not have a corresponding standard type/format:"properties": { ... "myProperty": { ...Foo's subschema or subschema ref (see previous rule)... }, ... }
"properties": { "myProperty1": { "type": "string", "format": "uri" }, "myProperty2": { "$ref": "#/$defs/Foo" } }
-
1
: same as above, but in this case, the property name must be included in therequired
array."properties": { ... "myProperty": { ...Foo's subschema or subschema ref (see first property mapping rule)... }, ... }, "required": ["myProperty", ...]
-
*
: the JSON property type is an array of theFoo
's JSON schema type definition but the property name is not included in therequired
array of the subschema:e.g. for two multi-valued UML properties, one of which does not have a corresponding standard type/format:"properties": { ... "myProperty": { "type": "array", "items": {...Foo's subschema or subschema ref (see first property mapping rule)...}, "unevaluatedItems": false }, ... }
"properties": { "myProperty1": { "type": "array", "items": {"type": "string", "format": "uri"}, "unevaluatedItems": false }, "myProperty2": { "type": "array", "items": {"$ref": "#/$defs/Foo"}, "unevaluatedItems": false } }
-
1..*
: same as above, but the array type definition has"minItems": 1
and the property name must be included in therequired
array of the subschema:"properties": { ... "myProperty": { "type": "array", "minItems": 1, "items": {...Foo's subschema or subschema ref (see previous rule)...}, "unevaluatedItems": false }, ... }, "required": ["myProperty", ...]
-
- 5.3. If the UML property has a default value, use the
default
keyword in JSON schema to specify the default value as well.
- 5.1. The Property is mapped to a JSON property in the JSON object type definition as follows:
-
If the UML Datatype
Foo
is stereotyped as<<AnyMetaProperty>>
(allows any meta-property besides defined ones if there is any, i.e. any JSON property may be added), then set"additionalProperties"=true
in Foo's subschema.- If
Foo
is also stereotyped asAnyProperty
and AnyProperty stereotype's propertyoneAndOnly
istrue
(one and only one other property is allowed), then return an error Unsupported as this case is not supposed to exist in the data model.
Else (
Foo
has noAnyMetaProperty
stereotype):- 6.1. If
Foo
is stereotyped as<<AnyProperty>>
(allows any non-meta property besides defined ones), then:-
6.1.1. If AnyProperty stereotype's
oneAndOnly="false"
(i.e. it allows any property besides the Datatype's defined properties if there is any, which means any JSON property may be added in the schema), then set"additionalProperties"=true
in Foo's schema. -
6.1.2. Else (oneAndOnly=true, i.e. only one other property): set
"additionalProperties"=false
, and:- 6.1.2.1. If
Foo
has optional properties: return the error Unsupported (not allowed in the data model) (Content
Datatype is the onlyAnyProperty
with oneAndOnly=true in the whole data model and indeed has no optional property) - 6.1.2.2. Else (
Foo
has no optional property, only required properties) set"minProperties" = "maxProperties" = number_of_defined_properties + 1
in theFoo
's schema.
- 6.1.2.1. If
-
- If