Skip to content

Commit 0fe5ab6

Browse files
committed
RD: Add CDDL file for security policies, small changes to policy file format
1 parent fd5d83f commit 0fe5ab6

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

aiocoap/cli/rd.py

+28-13
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
Policies for the default sector/no sector (if no sector is set) can be defined
7373
using the special ":default:" sector name.
7474
Policies that should apply to all clients even if they don't have any
75-
credentials (default policies) can be set using the special "*" credential
75+
credentials (default policies) can be set using the special ":default:" credential
7676
reference/claim.
7777
7878
If a client has multiple claims/multiple policies apply (e.g. the default
@@ -94,12 +94,12 @@
9494
}
9595
}
9696
},
97-
"policies": {
97+
"default_policies": {
9898
":key_2": {
9999
"write": true,
100100
"create": true
101101
},
102-
"*": {
102+
":default:": {
103103
"read": true,
104104
"write": false,
105105
"create": false
@@ -161,6 +161,20 @@
161161

162162
IMMUTABLE_PARAMETERS = ('ep', 'd', 'proxy')
163163

164+
# Sector key in the security policy configuration whose value should be used
165+
# for the "default" sector (i.e. if no sector is set).
166+
# Might need to be changed if there is a situation where ":default:" is used
167+
# as an actual sector name.
168+
DEFAULT_SECTOR_KEY = ':default:'
169+
170+
# Claim/credential reference key in the policy map whose value should be
171+
# treated as the "default" permissions for users that don't have any claims.
172+
# Might need to be changed if there is a situation where ":default:" is used
173+
# as an actual claim name (even though this can also be fixed by just using
174+
# a different name, since the claim names are only used internally and
175+
# arbritrarily set in the credentials file).
176+
DEFAULT_CLAIM_KEY = ':default:'
177+
164178
def query_split(msg):
165179
"""Split a message's query up into (key, [*value]) pairs from a
166180
?key=value&key2=value2 style Uri-Query options.
@@ -263,16 +277,16 @@ def _read_policy_entries(policy_data):
263277
sectors = dict()
264278
for sector_name, sector_data in data['sectors'].items():
265279
endpoints = dict()
266-
for endpoint_name, endpoint_data in sector_data['endpoints'].items():
267-
ep_policies = {cred_ref if cred_ref != "*" else None: _read_policy_entries(policy_data) for cred_ref, policy_data in endpoint_data['policies'].items()}
280+
for endpoint_name, endpoint_data in sector_data.get('endpoints', dict()).items():
281+
ep_policies = {cred_ref if cred_ref != DEFAULT_CLAIM_KEY else None: _read_policy_entries(policy_data) for cred_ref, policy_data in endpoint_data['policies'].items()}
268282
endpoints[endpoint_name] = cls.EndpointPolicy(ep_policies)
269283

270-
sec_policies = {cred_ref if cred_ref != "*" else None: _read_policy_entries(policy_data) for cred_ref, policy_data in sector_data['policies'].items()}
271-
if sector_name == ":default:":
284+
sec_policies = {cred_ref if cred_ref != DEFAULT_CLAIM_KEY else None: _read_policy_entries(policy_data) for cred_ref, policy_data in sector_data['default_policies'].items()}
285+
if sector_name == DEFAULT_SECTOR_KEY:
272286
sector_name = None
273287
sectors[sector_name] = cls.SectorPolicy(sec_policies, endpoints)
274288

275-
return cls(True, sectors, True if 'registrar_has_permissions' not in data else data['registrar_has_permissions'])
289+
return cls(True, sectors, data.get('registrar_has_permissions', True))
276290

277291
def __init__(self, enable, sectors=None, registrar_full_permissions=True):
278292
self.enable = enable
@@ -687,18 +701,19 @@ async def render_post(self, request):
687701

688702
return aiocoap.Message(code=aiocoap.CREATED, location_path=regresource.path)
689703

690-
class RegistrationResource(Resource):
704+
class RegistrationResource(ThingWithCommonRD, Resource):
691705
"""The resource object wrapping a registration is just a very thin and
692706
ephemeral object; all those methods could just as well be added to
693707
Registration with `s/self.reg/self/g`, making RegistrationResource(reg) =
694708
reg (or handleded in a single RegistrationDispatchSite), but this is kept
695709
here for better separation of model and interface."""
696710

697-
def __init__(self, registration):
711+
def __init__(self, common_rd, registration):
712+
super().__init__(common_rd)
698713
self.reg = registration
699714

700715
def _get_permissions(self, request):
701-
is_registrar = request.remote == self.reg.registrar
716+
is_registrar = type(request.remote) is type(self.reg.registrar) and request.remote == self.reg.registrar
702717
return self.common_rd.policy.get_permissions(request.remote.authenticated_claims,
703718
sector_name=self.reg.d,
704719
endpoint_name=self.reg.ep,
@@ -709,7 +724,7 @@ async def render_get(self, request):
709724
if not self._get_permissions(request) & CommonRD.SecurityPolicy.Permissions.READ:
710725
raise error.Unauthorized("Operation not allowed due to security policy")
711726

712-
return link_format_from_message(request, self.reg.links)
727+
return link_format_to_message(request, self.reg.links)
713728

714729
def _update_params(self, msg):
715730
query = query_split(msg)
@@ -754,7 +769,7 @@ async def render(self, request):
754769
except KeyError:
755770
raise error.NotFound
756771

757-
entity = RegistrationResource(entity)
772+
entity = RegistrationResource(self.common_rd, entity)
758773

759774
return await entity.render(request.copy(uri_path=()))
760775

aiocoap/cli/securitypolicy.cddl

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
security-policy = {
2+
"sectors": sector-map,
3+
? "registrar_has_permissions": bool, ; Will default to "true" if not defined
4+
}
5+
6+
sector-map = {
7+
* tstr => sector-policy,
8+
}
9+
10+
sector-policy = {
11+
? "endpoints": endpoint-map,
12+
? "default_policies": policy-map
13+
}
14+
15+
endpoint-map = {
16+
* tstr => endpoint-policy
17+
}
18+
19+
endpoint-policy = {
20+
"policies": policy-map
21+
}
22+
23+
; These are the same as in credentials.cddl
24+
claim = uripattern / credential-reference
25+
uripattern = tstr .regexp "[^:]"
26+
credential-reference = tstr .regexp ":.+"
27+
28+
policy-map = {
29+
* claim => policy
30+
}
31+
32+
policy = {
33+
? "write": bool, ; Will default to "false" if not defined
34+
? "read": bool, ; Will default to "false" if not defined
35+
? "create": bool, ; Will default to "false" if not defined
36+
}

0 commit comments

Comments
 (0)