Party
Type
Usage
NPL provides a built-in type Party
for parties. Parties represent entities that interact with protocols. The protocol
parties are declared in the protocol header as special protocol parameters.
In the following example issuer
and payee
represent the parties on the protocol Iou
.
protocol[issuer, payee] Iou() {
permission[issuer] pay() {
// ...
};
permission[payee] forgive() {
// ...
};
};
See protocol for more information on how to use parties.
Claims: entity and access
The NPL party type represents these entities with the use of claims. These claims form a simplified version of attribute based access control (ABAC). This, in turn, provides a means to determine whether the party has rights to access a given protocol or access its action(s). Within NPL these claims are split into two types, entity and access.
See authorization and authentication for more about entity and access.
Entity claims indicate the essential claims necessary to identify the entity that the party represents. Once created and bound to a protocol, during a protocol instantiation, a party's entity claims cannot be modified. The claims can only be changed by replacing the party itself by performing a transfer of ownership, or via migration. More about Transfer of ownership.
Access claims represent the elements that need the flexibility to change and reflect the roles and responsibilities the party can perform on behalf of the entity. Access claims can be changed but only by the user whose JWT claims match the original claims of the NPL party. This can be done by using the engine API endpoint for changing protocol access.
Calling party and bound party
Calling party - The party initiating the action/permission. As previously stated, a party in NPL is represented as claims.
Bound party - The party/claims specified during protocol instantiation and when changing access claims via the API. This is the party used to determine if the calling party has access to the given resource.
The claims are evaluated to determine if the calling party is authorized to access the given protocol. To understand how claims are matched and party access is determined, see claims evaluation
Note:
NPL still supports the legacy party constant (shown below) from within NPL. It is considered bad practice except in testing.
const PARTY = 'Joe';
Even though it is shown as a literal value, in the system it has the following claims:
{
"entity": {
"party": "Joe"
},
"access": {}
}
Constraints
Due to its prominent role in NPL, the Party
type/value cannot be used in the following situations:
- Protocol parameters cannot be of type
Party
. - Regular (non-party) protocol fields cannot contain a value of type
Party
. - Permission, obligation, notification parameters as well as return types are not allowed to be of the
Party
type.
Party
can however be used as a function parameter and return type.
// Illegal Party parameter type.
notification SayHello(p: Party) returns Party; // Illegal Party return type.
protocol[issuer, payee] Iou(illegalPartyAsProtocolParameter: Party) { // Illegal parameter type.
var illegalPartyInField = issuer; // Illegal field value.
// Illegal parameter type and return type.
permission[issuer] pay(illegalPartyAsActionParameter: Party) returns Party {};
// Legal return type.
function check(legalPartyAsFunctionParameter: Party) returns Map<Text, Party> {
// Legal local variable.
var m = mapOf(Pair { first: "someone", second: legalPartyAsFunctionParameter });
// Legal return type.
return m;
};
}
Methods
sameEntityAs
<function> Indicates whether the receiver party and the given party's entity claims are identical to each other.
Receiver
Party
Arguments
otherParty - Party - a party containing the claims to compare to
Returns
Boolean - 'true' if both parties' entity claims are identical.
Usage
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Manager")),
Pair("name", setOf("Sally"))
)
)
.sameEntityAs(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
) == true
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar"))
),
accessClaims = mapOf(
Pair("name", setOf("Alfred"))
)
)
.sameEntityAs(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Manager")),
Pair("name", setOf("Sally"))
)
)
) == false
containsEntityValuesOf
<function> Indicates whether all of this party's entity claims are present in the given party's entity.
Receiver
Party
Arguments
otherParty - Party - a party containing the claims to which the receiver party will be compared
Returns
Boolean - 'true' if the entity claims and respective values of otherParty are present in this party's entity claims.
Usage
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Manager")),
Pair("name", setOf("Sally"))
)
)
.containsEntityValuesOf(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
) == true
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("access", setOf("Super Secret"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Joe"))
)
)
.containsEntityValuesOf(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
) == true
// Joe's entity claims contain all the entity values
// of Mark's but also has an additional claim
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
.containsEntityValuesOf(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("access", setOf("Super Secret"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Joe"))
)
)
) == false // Mark is missing the 'access' claim in Joe's entity claims
isRepresentableBy
<function> Indicates whether or not the given claims can be used to represent the receiver party.
Receiver
Party
Arguments
fullClaims - Map<Text,Set<Text>> - a map of claims to which the receiver party will be compared
Returns
Boolean - 'true' if the given claims contain all of the entity claims and at least a single value for each access claim match.
Usage
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Manager")),
Pair("name", setOf("Sally"))
)
)
.isRepresentableBy(fullClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("name", setOf("Sally", "Joe")),
Pair("role", setOf("Manager"))
)) == true
// Sally can be represented by these claims because each of her entity claims
// match and her access claims also intersect the values given.
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
.isRepresentableBy(fullClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("name", setOf("Sally", "Joe")),
Pair("role", setOf("Manager"))
)) == false
// Mark would not be representable because even though his entity claims are contained within the
// given claims, his access claims do not intersect ('name' and 'role' values are missing).
mayRepresent
<function> Indicates if this party can act on behalf of the given party.
Receiver
Party
Arguments
otherParty - Party - a party containing the claims to which the receiver party will be compared
Returns
Boolean - 'true' if this party's entity claims contain all of the entity claims of otherParty and at least a single value for each access claim of both parties match.
Usage
There are two claim types, entity and access, as described here.
Mark's entity claims contain all the IT Group's entity (superset). Also, Mark's access claims contain one value for every claim in the IT Group (intersection). Since both of these conditions are true Mark can represent the IT Group.
Joe's situation is similar to Mark's except that he has more entity claims than the IT Group's entity (proper superset). Also, Joe's entity claims contain all the claims and matching values with the IT Group. The access key and values also exist for both Parties. Since both of the pre-requisites are true Joe can also represent the IT Group.
However, The IT group entity claims are missing the 'role' claim and therefore is not a superset and fails the qualification to represent Mark or Joe.
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
.mayRepresent(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf<Text, Set<Text>>(
Pair("name", setOf("Sally", "Mark", "Joe"))
)
)
) == true // Mark is a technician in the IT Group. Mark can represent the IT Group.
partyOf(
mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("access", setOf("Super Secret"))
),
mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Joe"))
)
)
.mayRepresent(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
// Access
accessClaims = mapOf<Text, Set<Text>>(
Pair("name", setOf("Sally", "Mark", "Joe"))
)
)
) == true // Joe is a senior technician on the IT Group, so he can also represent the IT Group
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf<Text, Set<Text>>(
Pair("name", setOf("Sally", "Mark", "Joe"))
)
)
.mayRepresent(
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Mark"))
)
)
) == false // Missing role claim
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT"))
),
accessClaims = mapOf<Text, Set<Text>>(
Pair("name", setOf("Sally", "Mark", "Joe"))
)
)
.mayRepresent(
partyOf(
mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar")),
Pair("department", setOf("IT")),
Pair("access", setOf("Super Secret"))
),
mapOf(
Pair("role", setOf("Technician")),
Pair("name", setOf("Joe"))
)
)
) == false // Missing role claim
entity
<function> Returns the receiver party's entity claims.
Receiver
Party
Returns
Map<Text, Set<Text>> - a map of the receiver party's entity claims and values
Usage
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar"))
),
accessClaims = mapOf(
Pair("name", setOf("Alfred"))
)
).entity()
== mapOf(Pair("iss", setOf("Noumena")), Pair("location", setOf("Baar")))
access
<function> Returns the receiver party's access claims.
Receiver
Party
Returns
Map<Text, Set<Text>> - a map of the receiver party's access claims and values
Usage
partyOf(
entityClaims = mapOf(
Pair("iss", setOf("Noumena")),
Pair("location", setOf("Baar"))
),
accessClaims = mapOf(
Pair("name", setOf("Alfred"))
)
).access()
== mapOf(Pair("name", setOf("Alfred")))
Inherited methods
toText
<function>
Obtain the Text
representation of this
.
Receiver
T
Type Arguments
T
Returns
Text - the Text
representation of this
Usage
Converts a Party
to Text
.
const sampleParty = 'Mario';
sampleParty.toText() == "Mario"