diff --git a/roles/kalite/defaults/main.yml b/roles/kalite/defaults/main.yml index 086f6839e..e2c992e1e 100644 --- a/roles/kalite/defaults/main.yml +++ b/roles/kalite/defaults/main.yml @@ -1,21 +1,29 @@ ---- # The values here are defaults. -# To override them edit the main var definitions in iiab/vars -kalite_version: "0.17.4" +# To override them edit the main var definitions in /opt/iiab/iiab/vars/local_vars.yml + +kalite_install: True +kalite_enabled: False + +kalite_version: "0.17.5" kalite_repo_url: "https://github.com/learningequality/ka-lite.git" +kalite_requirements: "https://raw.githubusercontent.com/learningequality/ka-lite/master/requirements.txt" + kalite_venv: "/usr/local/kalite/venv" kalite_program: "{{ kalite_venv }}/bin/kalite" -kalite_requirements: "https://raw.githubusercontent.com/learningequality/ka-lite/master/requirements.txt" kalite_root: "/library/ka-lite" + +kalite_server_port: 8008 +kalite_admin_user: Admin +kalite_admin_password: changeme + +# Unused in 2018; but remain as placeholders for Fedora 18 legacy (XO laptops) +kalite_cron_enabled: False kalite_user: kalite # obtain a password hash with - python -c 'import crypt; print crypt.crypt("", "$6$<salt>")' kalite_password_hash: $6$<salt>$KHET0XRRsgAY.wOWyTOI3W7dyDh0ESOr48uI5vtk2xdzsU7aw0TF4ZkNuM34RmHBGMJ1fTCmOyVobo0LOhBlJ/ kalite_password: kalite -kalite_admin_user: Admin -kalite_admin_password: changeme -kalite_server_name: kalite -kalite_server_port: 8008 -kalite_enabled: False -kalite_cron_enabled: False -khan_assessment_install: True -khan_assessment_url: "http://pantry.learningequality.org/downloads/ka-lite/0.16/content/khan_assessment.zip" + +# Unused in 2018 +# kalite_server_name: kalite +# khan_assessment_install: True +# khan_assessment_url: "http://pantry.learningequality.org/downloads/ka-lite/0.16/content/khan_assessment.zip" diff --git a/roles/kalite/tasks/main.yml b/roles/kalite/tasks/main.yml index 35f1932f7..84c508fe1 100644 --- a/roles/kalite/tasks/main.yml +++ b/roles/kalite/tasks/main.yml @@ -47,13 +47,9 @@ value: '"KA Lite is a server to present Khan Academy videos offline and to download them."' - option: path value: "{{ kalite_root }}" - - option: server_name - value: "{{ kalite_server_name }}" - option: port value: "{{ kalite_server_port }}" - option: enabled value: "{{ kalite_enabled }}" - option: cron_enabled value: "{{ kalite_cron_enabled }}" - - option: khan_assessment_install - value: "{{ khan_assessment_install }}" diff --git a/roles/network/defaults/main.yml b/roles/network/defaults/main.yml index 4524918df..55c2ffff1 100644 --- a/roles/network/defaults/main.yml +++ b/roles/network/defaults/main.yml @@ -71,3 +71,10 @@ named_enabled: True dnsmasq_enabled: False dnsmasq_install: False captive_portal_enabled: False + +# for simple python captive portal +py_captive_portal_install: True +py_captive_portal_enabled: True +py_captive_portal_port: "9090" +py_captive_portal_username: "Admin" +py_captive_portal_password: "changeme" diff --git a/roles/network/tasks/captive_portal.yml b/roles/network/tasks/captive_portal.yml new file mode 100644 index 000000000..8dad37fa7 --- /dev/null +++ b/roles/network/tasks/captive_portal.yml @@ -0,0 +1,37 @@ +- name: Create directory for captive portal script + file: path=/opt/iiab/captive-portal state=directory + when: py_captive_portal_install + +- name: Copy captive portal script + template: + src: roles/network/templates/captive_portal/captive_portal.py.j2 + dest: /opt/iiab/captive-portal/captive_portal.py + owner: root + group: root + mode: 0740 + when: py_captive_portal_install + +- name: Copy captive portal service file + template: + src: roles/network/templates/captive_portal/captive_portal.service.j2 + dest: /etc/systemd/system/captive_portal.service + owner: root + group: root + mode: 0644 + when: py_captive_portal_install + +- name: Enable captive_portal after copying files + service: name=captive_portal.service enabled=yes + when: py_captive_portal_install and py_captive_portal_enabled + +- name: Start captive_portal after copying files + service: name=captive_portal.service state=started + when: py_captive_portal_install and py_captive_portal_enabled + +- name: Disable captive_portal after copying files + service: name=captive_portal.service enabled=no + when: py_captive_portal_install and py_captive_portal_enabled + +- name: Stop captive_portal after copying files + service: name=captive_portal.service state=started + when: py_captive_portal_install and py_captive_portal_enabled diff --git a/roles/network/tasks/enable_services.yml b/roles/network/tasks/enable_services.yml index 4628874af..5660691c7 100644 --- a/roles/network/tasks/enable_services.yml +++ b/roles/network/tasks/enable_services.yml @@ -27,6 +27,7 @@ group=root mode={{ item.mode }} with_items: + - { src: 'named/named-iiab.conf.j2' , dest: '/etc/named-iiab.conf' , mode: '0644' } - { src: 'named/school.local.zone.db' , dest: '/var/named-iiab/' , mode: '0644' } - { src: 'named/school.internal.zone.db' , dest: '/var/named-iiab/' , mode: '0644' } diff --git a/roles/network/tasks/main.yml b/roles/network/tasks/main.yml index 6e73f7d4c..3d2e7ec42 100644 --- a/roles/network/tasks/main.yml +++ b/roles/network/tasks/main.yml @@ -74,6 +74,14 @@ include_tasks: squid.yml when: FQDN_changed and squid_install and iiab_stage|int == 9 +#- name: FOREFULLY ENABLE CAPTIVE PORTAL +# set_fact: +# py_captive_portal_install: True + +- name: (Re)Installing captive portal + include_tasks: captive_portal.yml + when: py_captive_portal_install + #### start services - include_tasks: avahi.yml tags: diff --git a/roles/network/templates/captive_portal/captive_portal.py.j2 b/roles/network/templates/captive_portal/captive_portal.py.j2 new file mode 100755 index 000000000..22ad1f009 --- /dev/null +++ b/roles/network/templates/captive_portal/captive_portal.py.j2 @@ -0,0 +1,97 @@ +#!/usr/bin/python + +# Captive portal script adapted from https://github.com/nikosft/captive-portal + +import subprocess +import BaseHTTPServer +import cgi + +# These variables are used as settings +PORT = int("{{ py_captive_portal_port }}") # the port in which the captive portal web server listens +IFACE = "{{ iiab_lan_iface }}" # the interface that captive portal protects +IP_ADDRESS = "{{ lan_ip }}" # the ip address of the captive portal (it can be the IP of IFACE) + +''' +This it the http server used by the the captive portal +''' +class CaptivePortal(BaseHTTPServer.BaseHTTPRequestHandler): + #this is the index of the captive portal + #it simply redirects the user to the to login page + html_redirect = """ + <html> + <head> + <meta http-equiv="refresh" content="0; url=http://%s:%s/login" /> + </head> + <body> + <b>Redirecting to login page</b> + </body> + </html> + """%(IP_ADDRESS, PORT) + #the login page + html_login = """ + <html> + <body> + <b>Login Form</b> + <form method="POST" action="do_login"> + Username: <input type="text" name="username"><br> + Password: <input type="password" name="password"><br> + <input type="submit" value="Submit"> + </form> + </body> + </html> + """ + + ''' + if the user requests the login page show it, else + use the redirect page + ''' + def do_GET(self): + path = self.path + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + if path == "/login": + self.wfile.write(self.html_login) + else: + self.wfile.write(self.html_redirect) + ''' + this is called when the user submits the login form + ''' + def do_POST(self): + self.send_response(200) + self.send_header("Content-type", "text/html") + self.end_headers() + form = cgi.FieldStorage( + fp=self.rfile, + headers=self.headers, + environ={'REQUEST_METHOD':'POST', + 'CONTENT_TYPE':self.headers['Content-Type'], + }) + username = form.getvalue("username") + password = form.getvalue("password") + #dummy security check + if username == '{{ py_captive_portal_username }}' and password == '{{ py_captive_portal_password }}': + #authorized user + remote_IP = self.client_address[0] + print 'New authorization from '+ remote_IP + print 'Updating IP tables' + subprocess.call(["iptables","-t", "nat", "-I", "PREROUTING","1", "-s", remote_IP, "-j" ,"ACCEPT"]) + subprocess.call(["iptables", "-I", "FORWARD", "-s", remote_IP, "-j" ,"ACCEPT"]) + self.wfile.write("You are now authorized. Navigate to any URL") + else: + #show the login form + self.wfile.write(self.html_login) + + #the following function makes server produce no output + #comment it out if you want to print diagnostic messages + #def log_message(self, format, *args): + # return + +print "Starting captive portal web server" +httpd = BaseHTTPServer.HTTPServer(('', PORT), CaptivePortal) + +try: + httpd.serve_forever() +except KeyboardInterrupt: + pass +httpd.server_close() diff --git a/roles/network/templates/captive_portal/captive_portal.service.j2 b/roles/network/templates/captive_portal/captive_portal.service.j2 new file mode 100644 index 000000000..03f3c33d5 --- /dev/null +++ b/roles/network/templates/captive_portal/captive_portal.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Captive portal +After=syslog.target + +[Service] +Type=simple +User=root +Group=root +WorkingDirectory=/opt/iiab/captive-portal +ExecStart=/opt/iiab/captive-portal/captive_portal.py +StandardOutput=syslog +StandardError=syslog + +[Install] +WantedBy=multi-user.target diff --git a/roles/network/templates/gateway/iiab-gen-iptables b/roles/network/templates/gateway/iiab-gen-iptables index 7ec8f3bf0..0e456dab1 100755 --- a/roles/network/templates/gateway/iiab-gen-iptables +++ b/roles/network/templates/gateway/iiab-gen-iptables @@ -60,6 +60,7 @@ kalite_server_port={{ kalite_server_port }} sugarizer_port={{ sugarizer_port }} block_DNS={{ block_DNS }} captive_portal_enabled={{ captive_portal_enabled }} +py_captive_portal_enabled={{ py_captive_portal_enabled }} echo "Lan is $lan and WAN is $wan" # @@ -101,12 +102,13 @@ $IPTABLES -A FORWARD -i $wan -o $lan -m state --state ESTABLISHED,RELATED -j ACC #Block https traffic except if directed at server if [ "$gw_block_https" == "True" ]; then - $IPTABLES -A FORWARD -p tcp ! -d 172.18.96.1 --dport 443 -j DROP + $IPTABLES -A FORWARD -p tcp ! -d {{ lan_ip }} --dport 443 -j DROP fi # Allow outgoing connections from the LAN side. -$IPTABLES -A FORWARD -i $lan -o $wan -j ACCEPT - +if ! [ "$py_captive_portal_enabled" == "True" ];then + $IPTABLES -A FORWARD -i $lan -o $wan -j ACCEPT +fi # Don't forward from the outside to the inside. $IPTABLES -A FORWARD -i $wan -o $lan -j DROP $IPTABLES -A INPUT -i $wan -j DROP @@ -122,8 +124,11 @@ if [ "$captive_portal_enabled" == "True" ];then $IPTABLES -t mangle -A internet -j MARK --set-mark 99 $IPTABLES -t nat -A PREROUTING -i {{ iiab_lan_iface }} -p tcp -m mark --mark 99 -m tcp --dport 80 -j DNAT --to-destination {{ lan_ip }} +elif [ "py_$captive_portal_enabled" == "True" ];then + $IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d {{ lan_ip }} -j DNAT --to {{ lan_ip }}:{{ py_captive_portal_port }} + elif [ "$HTTPCACHE_ON" == "True" ]; then - $IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d 172.18.96.1 -j DNAT --to 172.18.96.1:3128 + $IPTABLES -t nat -A PREROUTING -i $lan -p tcp --dport 80 ! -d {{ lan_ip }} -j DNAT --to {{ lan_ip }}:3128 fi # Enable routing. diff --git a/roles/network/templates/network/dnsmasq.conf.j2 b/roles/network/templates/network/dnsmasq.conf.j2 index 282c0b222..afd148c89 100644 --- a/roles/network/templates/network/dnsmasq.conf.j2 +++ b/roles/network/templates/network/dnsmasq.conf.j2 @@ -4,7 +4,7 @@ bogus-priv #server=/{{ iiab_domain }}/{{ iiab_hostname }} # Add local-only domains here, queries in these domains are answered from /etc/hosts or DHCP only. local=/{{ iiab_domain }}/ -{% if captive_portal_enabled == "True" %} +{% if dns_jail_enabled %} # Make all host names resolve to the Raspberry Pi's IP address address=/#/{{ lan_ip }} {% endif %} diff --git a/vars/default_vars.yml b/vars/default_vars.yml index ebe72e509..1734e1228 100644 --- a/vars/default_vars.yml +++ b/vars/default_vars.yml @@ -103,9 +103,12 @@ dhcpd_enabled: False named_install: True named_enabled: True block_DNS: False +# Captive Portal highly experimental as of July 2018: https://github.com/iiab/iiab/pull/870 +py_captive_portal_install: True +py_captive_portal_enabled: False # dnsmasq -dnsmasq_install: False +dnsmasq_install: True dnsmasq_enabled: False # Captive Portal highly experimental as of June 2018: https://github.com/iiab/iiab/issues/608 @@ -295,14 +298,16 @@ wordpress_enabled: False # KA Lite kalite_install: True +kalite_enabled: False +kalite_server_port: 8008 kalite_root: "/library/ka-lite" +# Unused in 2018; but remain as placeholders for Fedora 18 legacy (XO laptops) +kalite_cron_enabled: False kalite_user: kalite kalite_password_hash: $6$<salt>$KHET0XRRsgAY.wOWyTOI3W7dyDh0ESOr48uI5vtk2xdzsU7aw0TF4ZkNuM34RmHBGMJ1fTCmOyVobo0LOhBlJ/ kalite_password: kalite -kalite_server_name: kalite -kalite_server_port: 8008 -kalite_enabled: False -kalite_cron_enabled: False +# Unused in 2018 +# kalite_server_name: kalite # Kiwix kiwix_install: True diff --git a/vars/local_vars_big.yml b/vars/local_vars_big.yml index d89b264d5..db86484b7 100644 --- a/vars/local_vars_big.yml +++ b/vars/local_vars_big.yml @@ -159,6 +159,7 @@ wordpress_enabled: True kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True diff --git a/vars/local_vars_big_vpn.yml b/vars/local_vars_big_vpn.yml index 699ebc145..78399b980 100644 --- a/vars/local_vars_big_vpn.yml +++ b/vars/local_vars_big_vpn.yml @@ -159,6 +159,7 @@ wordpress_enabled: True kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True diff --git a/vars/local_vars_medium.yml b/vars/local_vars_medium.yml index 8e3b2cb0f..21f7556f5 100644 --- a/vars/local_vars_medium.yml +++ b/vars/local_vars_medium.yml @@ -159,6 +159,7 @@ wordpress_enabled: True kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True diff --git a/vars/local_vars_medium_vpn.yml b/vars/local_vars_medium_vpn.yml index bb5cfed17..70ec6105e 100644 --- a/vars/local_vars_medium_vpn.yml +++ b/vars/local_vars_medium_vpn.yml @@ -159,6 +159,7 @@ wordpress_enabled: True kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True diff --git a/vars/local_vars_min.yml b/vars/local_vars_min.yml index a29a150db..f41915947 100644 --- a/vars/local_vars_min.yml +++ b/vars/local_vars_min.yml @@ -159,6 +159,7 @@ wordpress_enabled: False kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True diff --git a/vars/local_vars_min_vpn.yml b/vars/local_vars_min_vpn.yml index 351e01b4a..f427a1888 100644 --- a/vars/local_vars_min_vpn.yml +++ b/vars/local_vars_min_vpn.yml @@ -159,6 +159,7 @@ wordpress_enabled: False kalite_install: True kalite_enabled: True +# Unused in 2018; but remains as placeholder for Fedora 18 legacy (XO laptops) kalite_cron_enabled: True kiwix_install: True