diff --git a/certidude/api/script.py b/certidude/api/script.py
index a78e7f7..a46a899 100644
--- a/certidude/api/script.py
+++ b/certidude/api/script.py
@@ -11,30 +11,28 @@ env = Environment(loader=FileSystemLoader(config.SCRIPT_DIR), trim_blocks=True)
class ScriptResource():
@whitelist_subject
def on_get(self, req, resp, cn):
- try:
- path, buf, cert, attribs = authority.get_attributes(cn)
- except IOError:
- raise falcon.HTTPNotFound()
- else:
- script = config.SCRIPT_DEFAULT
- tags = []
- try:
- for tag in attribs.get("user").get("xdg").get("tags").split(","):
- if "=" in tag:
- k, v = tag.split("=", 1)
- else:
- k, v = "other", tag
- if k == "script":
- script = v
- tags.append(dict(id=tag, key=k, value=v))
- except AttributeError: # No tags
- pass
+ path, buf, cert, attribs = authority.get_attributes(cn)
+ # TODO: are keys unique?
+ named_tags = {}
+ other_tags = []
- resp.set_header("Content-Type", "text/x-shellscript")
- resp.body = env.get_template(script).render(
- authority_name=const.FQDN,
- common_name=cn,
- tags=tags,
- attributes=attribs.get("user").get("machine"))
- logger.info("Served script %s for %s at %s" % (script, cn, req.context["remote_addr"]))
+ try:
+ for tag in attribs.get("user").get("xdg").get("tags").split(","):
+ if "=" in tag:
+ k, v = tag.split("=", 1)
+ named_tags[k] = v
+ else:
+ other_tags.append(v)
+ except AttributeError: # No tags
+ pass
+
+ script = named_tags.get("script", config.SCRIPT_DEFAULT)
+ resp.set_header("Content-Type", "text/x-shellscript")
+ resp.body = env.get_template(script).render(
+ authority_name=const.FQDN,
+ common_name=cn,
+ other_tags=other_tags,
+ named_tags=named_tags,
+ attributes=attribs.get("user").get("machine"))
+ logger.info("Served script %s for %s at %s" % (script, cn, req.context["remote_addr"]))
# TODO: Assert time is within reasonable range
diff --git a/certidude/static/views/attributes.html b/certidude/static/views/attributes.html
index 5e37128..9423b3f 100644
--- a/certidude/static/views/attributes.html
+++ b/certidude/static/views/attributes.html
@@ -1,3 +1,3 @@
{% for key, value in certificate.attributes %}
-{{ value }}
+{{ value }}
{% endfor %}
diff --git a/certidude/templates/script/default.sh b/certidude/templates/script/default.sh
index 2729274..06af6f7 100644
--- a/certidude/templates/script/default.sh
+++ b/certidude/templates/script/default.sh
@@ -1,10 +1,14 @@
#!/bin/sh
# Tags:
-{% for tag in tags %}
+{% for key, value in named_tags.items() %}
+# {{ key }} -> {{ value }}
+{% endfor %}
+{% for tag in other_tags %}
# {{ tag }}
{% endfor %}
+# Submit some stats to CA
curl http://{{ authority_name }}/api/signed/{{ common_name }}/attr -X POST -d "\
dmi.product_name=$(cat /sys/class/dmi/id/product_name)&\
dmi.product_serial=$(cat /sys/class/dmi/id/product_serial)&\
diff --git a/certidude/templates/script/openwrt.sh b/certidude/templates/script/openwrt.sh
index 61f7664..1c2e4b5 100644
--- a/certidude/templates/script/openwrt.sh
+++ b/certidude/templates/script/openwrt.sh
@@ -10,13 +10,13 @@ for band in 2ghz 5ghz; do
uci set wireless.lan$band.mode=ap
uci set wireless.lan$band.device=radio$band
uci set wireless.lan$band.encryption=psk2
- {% if attributes.wireless.protected and attributes.wireless.protected.ssid %}
- uci set wireless.lan$band.ssid={{ attrbutes.wireless.protected.ssid }}
+ {% if named_tags and named_tags.wireless and named_tags.wireless.protected and named_tags.wireless.protected.ssid %}
+ uci set wireless.lan$band.ssid={{ named_tags.wireless.protected.ssid }}
{% else %}
uci set wireless.lan$band.ssid=$(uci get system.@system[0].hostname)-protected
{% endif %}
- {% if attributes.wireless.protected and attributes.wireless.protected.psk %}
- uci set wireless.lan$band.key={{ attributes.wireless.protected.psk }}
+ {% if named_tags and named_tags.wireless and named_tags.wireless.protected and named_tags.wireless.protected.psk %}
+ uci set wireless.lan$band.key={{ named_tags.wireless.protected.psk }}
{% else %}
uci set wireless.lan$band.key=salakala
{% endif %}
@@ -29,8 +29,8 @@ for band in 2ghz 5ghz; do
uci set wireless.guest$band.mode=ap
uci set wireless.guest$band.device=radio$band
uci set wireless.guest$band.encryption=none
- {% if attributes.wireless.public and attributes.wireless.public.ssid %}
- uci set wireless.guest$band.ssid={{ attrbutes.wireless.public.ssid }}
+ {% if named_tags and named_tags.wireless and named_tags.wireless.public and named_tags.wireless.public.ssid %}
+ uci set wireless.guest$band.ssid={{ named_tags.wireless.public.ssid }}
{% else %}
uci set wireless.guest$band.ssid=$(uci get system.@system[0].hostname)-public
{% endif %}
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 4e7a8e0..6f1eaf9 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -493,40 +493,6 @@ def test_cli_setup_authority():
r = client().simulate_get("/api/signed/nonexistant/attr/", headers={"Authorization":admintoken})
assert r.status_code == 404, r.text
- # Insert lease
- r = client().simulate_get("/api/signed/test/script/")
- assert r.status_code == 403, r.text # script not authorized
- r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":admintoken})
- assert r.status_code == 404, r.text
- r = client().simulate_post("/api/lease/",
- query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8",
- headers={"Authorization":admintoken})
- assert r.status_code == 200, r.text # lease update ok
- r = client().simulate_get("/api/signed/nonexistant/script/")
- assert r.status_code == 404, r.text # cert not found
- r = client().simulate_get("/api/signed/test/script/")
- assert r.status_code == 200, r.text # script render ok
- assert "curl http://ca.example.lan/api/signed/test/attr " in r.text, r.text
-
- r = client().simulate_post("/api/lease/",
- query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8&serial=0",
- headers={"Authorization":admintoken})
- assert r.status_code == 403, r.text # invalid serial number supplied
- r = client().simulate_post("/api/lease/",
- query_string = "client=test&inner_address=1.2.3.4&outer_address=8.8.8.8",
- headers={"Authorization":admintoken})
- assert r.status_code == 200, r.text # lease update ok
-
- # Test lease retrieval
- r = client().simulate_get("/api/signed/test/lease/")
- assert r.status_code == 401, r.text
- r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":usertoken})
- assert r.status_code == 403, r.text
- r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":admintoken})
- assert r.status_code == 200, r.text
- assert r.headers.get('content-type') == "application/json; charset=UTF-8"
-
-
# Tags should not be visible anonymously
r = client().simulate_get("/api/signed/test/tag/")
assert r.status_code == 401, r.text
@@ -568,6 +534,56 @@ def test_cli_setup_authority():
assert r.status_code == 200, r.text
assert r.text == '[{"value": "Tartu", "key": "location", "id": "location=Tartu"}, {"value": "else", "key": "other", "id": "else"}]', r.text
+
+
+ # Test scripting
+ r = client().simulate_get("/api/signed/test/script/")
+ assert r.status_code == 403, r.text # script not authorized
+ r = client().simulate_get("/api/signed/nonexistant/script/")
+ assert r.status_code == 404, r.text # cert not found
+
+ # Insert lease
+ r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":admintoken})
+ assert r.status_code == 404, r.text
+ r = client().simulate_post("/api/lease/",
+ query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8",
+ headers={"Authorization":admintoken})
+ assert r.status_code == 200, r.text # lease update ok
+
+ # Test tagging integration in scripting framework
+ r = client().simulate_get("/api/signed/test/script/")
+ assert r.status_code == 200, r.text # script render ok
+ assert "curl http://ca.example.lan/api/signed/test/attr " in r.text, r.text
+ assert "Tartu" in r.text, r.text
+
+ r = client().simulate_post("/api/signed/test/tag/",
+ body="key=script&value=openwrt.sh",
+ headers={"content-type": "application/x-www-form-urlencoded", "Authorization":admintoken})
+ assert r.status_code == 200, r.text
+
+ r = client().simulate_get("/api/signed/test/script/")
+ assert r.status_code == 200, r.text # script render ok
+ assert "uci set " in r.text, r.text
+
+ # Test lease update
+ r = client().simulate_post("/api/lease/",
+ query_string = "client=test&inner_address=127.0.0.1&outer_address=8.8.8.8&serial=0",
+ headers={"Authorization":admintoken})
+ assert r.status_code == 403, r.text # invalid serial number supplied
+ r = client().simulate_post("/api/lease/",
+ query_string = "client=test&inner_address=1.2.3.4&outer_address=8.8.8.8",
+ headers={"Authorization":admintoken})
+ assert r.status_code == 200, r.text # lease update ok
+
+ # Test lease retrieval
+ r = client().simulate_get("/api/signed/test/lease/")
+ assert r.status_code == 401, r.text
+ r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":usertoken})
+ assert r.status_code == 403, r.text
+ r = client().simulate_get("/api/signed/test/lease/", headers={"Authorization":admintoken})
+ assert r.status_code == 200, r.text
+ assert r.headers.get('content-type') == "application/json; charset=UTF-8"
+
# Tags can be deleted only by admin
r = client().simulate_delete("/api/signed/test/tag/else/")
assert r.status_code == 401, r.text
@@ -580,6 +596,9 @@ def test_cli_setup_authority():
r = client().simulate_delete("/api/signed/test/tag/location=Tartu/",
headers={"content-type": "application/x-www-form-urlencoded", "Authorization":admintoken})
assert r.status_code == 200, r.text
+ r = client().simulate_delete("/api/signed/test/tag/script=openwrt.sh/",
+ headers={"content-type": "application/x-www-form-urlencoded", "Authorization":admintoken})
+ assert r.status_code == 200, r.text
r = client().simulate_get("/api/signed/test/tag/", headers={"Authorization":admintoken})
assert r.status_code == 200, r.text
assert r.text == "[]", r.text