diff --git a/README.md b/README.md index 10384d33..9fc0d828 100644 --- a/README.md +++ b/README.md @@ -385,6 +385,10 @@ create an empty file named `playbook.yml` which contains the following: # the following line is needed only when an IP address is used as the inventory hostname vars: postfix_myhostname: localhost + # Enable the modules you want to use + openwisp2_network_topology: true + openwisp2_firmware_upgrader: true + openwisp2_radius: true ``` **Step 6**: Run the playbook @@ -401,88 +405,6 @@ username: admin password: admin ``` -Enabling the network topology module ------------------------------------- - -To enable the network topology module you need to set `openwisp2_network_topology` to `true` in -your `playbook.yml` file. Here's a short summary of how to do this: - -**Step 1**: [Install ansible](#install-ansible) - -**Step 2**: [Install this role](#install-this-role) - -**Step 3**: [Create inventory file](#create-inventory-file) - -**Step 4**: Create a playbook file with following contents: - -```yaml -- hosts: openwisp2 - become: "{{ become | default('yes') }}" - roles: - - openwisp.openwisp2 - vars: - openwisp2_network_topology: true -``` - -**Step 5**: [Run the playbook](#run-the-playbook) - -When the playbook is done running, if you got no errors you can login at: - - https://openwisp2.mydomain.com/admin - username: admin - password: admin - -Enabling the firmware upgrader module -------------------------------------- - -**Note**: It is encouraged that you read the [quick-start guide of openwisp-firmware-upgrader](https://github.com/openwisp/openwisp-firmware-upgrader#quickstart) -before going ahead. - -To enable the firmware upgrader module you need to set `openwisp2_firmware_upgrader` to `true` in -your `playbook.yml` file. Here's a short summary of how to do this: - -**Step 1**: [Install ansible](#install-ansible) - -**Step 2**: [Install this role](#install-this-role) - -**Step 3**: [Create inventory file](#create-inventory-file) - -**Step 4**: Create a playbook file with following contents: - -```yaml -- hosts: openwisp2 - become: "{{ become | default('yes') }}" - roles: - - openwisp.openwisp2 - vars: - openwisp2_firmware_upgrader: true -``` - -**Step 5**: [Run the playbook](#run-the-playbook) - -When the playbook is done running, if you got no errors you can login at: - - https://openwisp2.mydomain.com/admin - username: admin - password: admin - -**Note**: You can configure [openwisp-firmware-upgrader specific settings](https://github.com/openwisp/openwisp-firmware-upgrader#settings) -using `openwisp2_extra_django_settings` variable of this ansible role. -For example if you want to enable the [APIs of openwisp-firmware-upgrader](https://github.com/openwisp/openwisp-firmware-upgrader#rest-api), -you will update the above playbook as follows: - -```yaml -- hosts: openwisp2 - become: "{{ become | default('yes') }}" - roles: - - openwisp.openwisp2 - vars: - openwisp2_firmware_upgrader: true - openwisp2_extra_django_settings: - OPENWISP_USERS_AUTH_API: true - OPENWISP_FIRMWARE_UPGRADER_API: true -``` - Troubleshooting =============== @@ -579,12 +501,17 @@ Below are listed all the variables you can customize (you may also want to take - openwisp.openwisp2 vars: # openwisp-controler version - openwisp2_controller_version: "0.4" + openwisp2_controller_version: "0.8.1" # optional openwisp2 modules openwisp2_network_topology: false - openwisp2_network_topology_version: "0.4" + openwisp2_network_topology_version: "0.5.1" openwisp2_firmware_upgrader: false openwisp2_firmware_upgrader_version: "0.1" + openwisp2_radius_version: "0.1" + # Enable the modules you want to use + openwisp2_network_topology: true + openwisp2_firmware_upgrader: true + openwisp2_radius: true # you may replace the values of these variables with any URL # supported by pip (the python package installer) # use these to install forks, branches or development versions @@ -598,6 +525,7 @@ Below are listed all the variables you can customize (you may also want to take openwisp2_netjsonconfig_pip: false openwisp2_network_topology_pip: false openwisp2_firmware_upgrader_pip: false + openwisp2_radius_pip: false # by default python3 is used, if may need to set this to python2.7 for older systems openwisp2_python: python2.7 # customize the app_path @@ -719,13 +647,40 @@ Below are listed all the variables you can customize (you may also want to take # if set to True, will log all the celery events in the same log stream used by django # which will cause log lines to be written to "{{ openwisp2_path }}/log/openwisp2.log" # instead of "{{ openwisp2_path }}/log/celery.log" and "{{ openwisp2_path }}/log/celerybeat.log" - openwisp2_django_celery_logging: False + openwisp2_django_celery_logging: false # allow overriding default `postfix_smtp_sasl_auth_enable` variable postfix_smtp_sasl_auth_enable_override: yes # allow overriding postfix_smtpd_relay_restrictions postfix_smtpd_relay_restrictions_override: permit_mynetworks # allows overriding the default duration for keeping notifications openwisp2_notifications_delete_old_notifications: 10 + openwisp2_users_auth_api: true + openwisp2_radius_sms_backend: "sendsms.backends.console.SmsBackend" + openwisp2_radius_sms_token_max_ip_daily: 25 + openwisp2_freeradius_allowed_hosts: ["127.0.0.1"] + freeradius_dir: /etc/freeradius/3.0 + freeradius_mods_available_dir: "{{ freeradius_dir }}/mods-available" + freeradius_mods_enabled_dir: "{{ freeradius_dir }}/mods-enabled" + freeradius_sites_available_dir: "{{ freeradius_dir }}/sites-available" + freeradius_sites_enabled_dir: "{{ freeradius_dir }}/sites-enabled" + freeradius_sql: + driver: rlm_sql_sqlite + dialect: sqlite + host: "" + port: "" + dbname: "" + user: "" + password: "" + freeradius_rest: + url: "https://{{ inventory_hostname }}/api/v1/freeradius" + freeradius_clients_ip: "0.0.0.0/0" + freeradius_clients_key: "admin" + cron_delete_old_notifications: "'hour': 0, 'minute': 0" + cron_deactivate_expired_users: "'hour': 0, 'minute': 0" + cron_delete_old_users: "'hour': 0, 'minute': 10" + cron_cleanup_stale_radacct: "'hour': 0, 'minute': 20" + cron_delete_old_postauth: "'hour': 0, 'minute': 30" + cron_delete_old_radacct: "'hour': 0, 'minute': 40" ``` Support diff --git a/defaults/main.yml b/defaults/main.yml index 56a7ae57..bfe44d21 100755 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -2,9 +2,11 @@ openwisp2_python: python3 ansible_python_interpreter: /usr/bin/python3 openwisp2_network_topology: false openwisp2_firmware_upgrader: false +openwisp2_radius: false openwisp2_controller_version: "0.8.1" openwisp2_network_topology_version: "0.5.1" openwisp2_firmware_upgrader_version: "0.1" +openwisp2_radius_version: "0.1" openwisp2_controller_pip: false openwisp2_users_pip: false openwisp2_utils_pip: false @@ -13,6 +15,7 @@ openwisp2_django_loci_pip: false openwisp2_netjsonconfig_pip: false openwisp2_network_topology_pip: false openwisp2_firmware_upgrader_pip: false +openwisp2_radius_pip: false openwisp2_extra_python_packages: [bpython] openwisp2_extra_django_apps: [] openwisp2_extra_django_settings: {} @@ -88,5 +91,32 @@ openwisp2_celery_broker_url: redis://127.0.0.1:6379/3 openwisp2_celery_worker_prefetch_multiplier: 1 openwisp2_celery_task_acks_late: True openwisp2_celery_broker_max_tries: 10 -openwisp2_django_celery_logging: False +openwisp2_django_celery_logging: false postfix_smtpd_relay_restrictions_override: "permit_sasl_authenticated, permit_mynetworks, check_relay_domains, reject_unauth_destination, reject" +openwisp2_users_auth_api: true +openwisp2_radius_sms_backend: "sendsms.backends.console.SmsBackend" +openwisp2_radius_sms_token_max_ip_daily: 25 +openwisp2_freeradius_allowed_hosts: ["127.0.0.1"] +freeradius_dir: /etc/freeradius/3.0 +freeradius_mods_available_dir: "{{ freeradius_dir }}/mods-available" +freeradius_mods_enabled_dir: "{{ freeradius_dir }}/mods-enabled" +freeradius_sites_available_dir: "{{ freeradius_dir }}/sites-available" +freeradius_sites_enabled_dir: "{{ freeradius_dir }}/sites-enabled" +freeradius_sql: + driver: rlm_sql_sqlite + dialect: sqlite + host: "" + port: "" + dbname: "" + user: "" + password: "" +freeradius_rest: + url: "https://{{ inventory_hostname }}/api/v1/freeradius" +freeradius_clients_ip: "0.0.0.0/0" +freeradius_clients_key: "admin" +cron_delete_old_notifications: "'hour': 0, 'minute': 0" +cron_deactivate_expired_users: "'hour': 0, 'minute': 0" +cron_delete_old_users: "'hour': 0, 'minute': 10" +cron_cleanup_stale_radacct: "'hour': 0, 'minute': 20" +cron_delete_old_postauth: "'hour': 0, 'minute': 30" +cron_delete_old_radacct: "'hour': 0, 'minute': 40" diff --git a/handlers/main.yml b/handlers/main.yml index b36039ea..4e5d08eb 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -3,14 +3,33 @@ --- - name: reload systemd - systemd: daemon_reload=yes + systemd: + daemon_reload: yes when: ansible_distribution_release in ['bionic'] and ansible_service_mgr == 'systemd' - name: reload supervisor command: supervisorctl reload - name: restart nginx - service: name=nginx state=restarted + service: + name: nginx + state: restarted + +- name: start postgresql + service: + name: postgresql + state: started - name: start redis - service: name=redis state=started + service: + name: redis + state: started + +- name: update-ca-certificates + shell: /usr/sbin/update-ca-certificates + when: ansible_os_family == "Debian" + +- name: restart freeradius + service: + name: freeradius + state: restarted diff --git a/molecule/resources/converge.yml b/molecule/resources/converge.yml index e8ff2c84..fa80c09e 100644 --- a/molecule/resources/converge.yml +++ b/molecule/resources/converge.yml @@ -7,10 +7,13 @@ vars: openwisp2_network_topology: true openwisp2_firmware_upgrader: true + openwisp2_radius: true pre_tasks: - name: Update apt cache - apt: update_cache=true cache_valid_time=600 + apt: + update_cache: true + cache_valid_time: 600 when: ansible_os_family == 'Debian' - name: Remove the .dockerenv file diff --git a/tasks/apt.yml b/tasks/apt.yml index 577643a2..99505142 100644 --- a/tasks/apt.yml +++ b/tasks/apt.yml @@ -1,5 +1,6 @@ - name: Update APT package cache - apt: update_cache=yes + apt: + update_cache: yes changed_when: false retries: 5 delay: 10 @@ -81,6 +82,17 @@ until: result is success notify: reload systemd +- name: Install cairo + when: openwisp2_radius + apt: + name: + - libcairo2 + - libpango-1.0-0 + - libpangocairo-1.0-0 + - libgdk-pixbuf2.0-0 + - shared-mime-info + tags: [openwisp2, radius] + - name: Install mod-spatialite (may fail on older linux distros) when: openwisp2_database.engine == "django.contrib.gis.db.backends.spatialite" apt: name=libsqlite3-mod-spatialite diff --git a/tasks/django.yml b/tasks/django.yml index 61098abb..93035eb8 100644 --- a/tasks/django.yml +++ b/tasks/django.yml @@ -70,6 +70,14 @@ group: "{{ www_group }}" mode: 0664 +- name: storage.py + notify: reload supervisor + template: + src: openwisp2/storage.py + dest: "{{ openwisp2_path }}/openwisp2/storage.py" + group: "{{ www_group }}" + mode: 0664 + # set openwisp2_secret_key if not defined explicitly - import_tasks: django_secret_key.yml when: openwisp2_secret_key is not defined @@ -90,8 +98,8 @@ group: "{{ www_group }}" mode: 0664 -- name: start redis - service: name=redis state=started +- name: start redis for migration + meta: flush_handlers - name: migrate notify: reload supervisor diff --git a/tasks/freeradius-postgresql.yml b/tasks/freeradius-postgresql.yml new file mode 100644 index 00000000..868b2604 --- /dev/null +++ b/tasks/freeradius-postgresql.yml @@ -0,0 +1,43 @@ +--- +- name: Freeradius additional postgresql system packages + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + apt: + name: + - postgresql + - freeradius-postgresql + - libpq-dev + state: latest + notify: start postgresql + +- name: Install psycopg2 + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + pip: + name: psycopg2 + state: latest + retries: 5 + delay: 10 + register: result + until: result is success + notify: start postgresql + +- name: start postgresql for migration + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + meta: flush_handlers + +- name: Create freeradius database + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + become_user: postgres + become: true + postgresql_db: + name: "{{ freeradius_sql.dbname }}" + state: present + +- name: Create freeradius database user + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + become_user: postgres + become: true + postgresql_user: + db: "{{ freeradius_sql.dbname }}" + name: "{{ freeradius_sql.user }}" + password: "{{ freeradius_sql.password }}" + priv: ALL diff --git a/tasks/freeradius.yml b/tasks/freeradius.yml new file mode 100644 index 00000000..780a9e6e --- /dev/null +++ b/tasks/freeradius.yml @@ -0,0 +1,122 @@ +--- +- name: Freeradius system packages + when: openwisp2_radius + apt: + name: + - freeradius + - freeradius-rest + state: latest + notify: restart freeradius + +- import_tasks: freeradius-postgresql.yml + when: openwisp2_radius and freeradius_sql.dialect == "sqlite" + +- import_tasks: freeradius-postgresql.yml + when: openwisp2_radius and freeradius_sql.dialect == "postgresql" + +- name: Radius configurations + when: openwisp2_radius + template: + src: freeradius/radiusd.conf.j2 + dest: "{{ freeradius_dir }}/radiusd.conf" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius + +- name: Clients configuration + when: openwisp2_radius + template: + src: freeradius/clients.conf.j2 + dest: "{{ freeradius_dir }}/site" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius + +- name: Remove unnecessary modules + when: openwisp2_radius + file: + dest: "{{ item }}" + state: absent + with_items: + - "{{ freeradius_mods_enabled_dir }}/eap" + +- name: SQL configuration + when: openwisp2_radius + template: + src: freeradius/sql.j2 + dest: "{{ freeradius_mods_available_dir }}/sql" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius + +- name: Enable SQL module + when: openwisp2_radius + file: + src: "{{ freeradius_mods_available_dir }}/sql" + dest: "{{ freeradius_mods_enabled_dir }}/sql" + state: link + mode: 0640 + owner: freerad + group: freerad + +- name: SQL Counter module + when: openwisp2_radius + template: + src: freeradius/sql_counter.j2 + dest: "{{ freeradius_mods_available_dir }}/sql_counter" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius + +- name: Enable SQL Counter module + when: openwisp2_radius + file: + src: "{{ freeradius_mods_available_dir }}/sql_counter" + dest: "{{ freeradius_mods_enabled_dir }}/sql_counter" + state: link + mode: 0640 + owner: freerad + group: freerad + +- name: REST configuration + when: openwisp2_radius + template: + src: freeradius/rest.j2 + dest: "{{ freeradius_mods_available_dir }}/rest" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius + +- name: Enable REST module + when: openwisp2_radius + file: + src: "{{ freeradius_mods_available_dir }}/rest" + dest: "{{ freeradius_mods_enabled_dir }}/rest" + state: link + mode: 0640 + owner: freerad + group: freerad + +- name: Remove default site + when: openwisp2_radius + file: + dest: "{{ item }}" + state: absent + with_items: + - "{{ freeradius_sites_enabled_dir }}/default" + - "{{ freeradius_sites_enabled_dir }}/inner-tunnel" + +- name: Site configuration + when: openwisp2_radius + template: + src: freeradius/openwisp_site.j2 + dest: "{{ freeradius_sites_enabled_dir }}/openwisp_site" + mode: 0640 + owner: freerad + group: freerad + notify: restart freeradius diff --git a/tasks/main.yml b/tasks/main.yml index 73f212ae..1338b613 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -25,6 +25,9 @@ - import_tasks: django.yml tags: [openwisp2, django] +- import_tasks: freeradius.yml + tags: [openwisp2, freeradius] + - import_tasks: supervisor.yml tags: [openwisp2, supervisor] diff --git a/tasks/nginx.yml b/tasks/nginx.yml index c06c76fb..deb1133e 100644 --- a/tasks/nginx.yml +++ b/tasks/nginx.yml @@ -19,13 +19,24 @@ -out {{ openwisp2_ssl_cert }} \ -extensions v3_ca creates={{ openwisp2_ssl_cert }} args: - warn: False + warn: false notify: restart nginx +- name: Copy SSL cert to be added to trusted Cert (for freeradius) + copy: + src: "{{ openwisp2_ssl_cert }}" + dest: /usr/local/share/ca-certificates/openwisp-ssl-server.crt + remote_src: yes + owner: "root" + group: "root" + mode: "0644" + when: ansible_os_family == 'Debian' + notify: update-ca-certificates + - name: disable default nginx configuration file: - path: "/etc/nginx/sites-enabled/default" - state: absent + path: "/etc/nginx/sites-enabled/default" + state: absent - name: nginx site available template: diff --git a/tasks/pip.yml b/tasks/pip.yml index 6d290ccc..ff050dbe 100644 --- a/tasks/pip.yml +++ b/tasks/pip.yml @@ -52,6 +52,13 @@ - "{{ openwisp2_network_topology_pip }}" when: item is defined and item is string and openwisp2_network_topology +- name: Add openwisp_radius to custom package list if set and enabled + set_fact: + openwisp2_python_packages: "{{ openwisp2_python_packages + [item] }}" + with_items: + - "{{ openwisp2_radius_pip }}" + when: item is defined and item is string and openwisp2_radius + - name: Add firmware_upgrader to custom package list if set and enabled set_fact: openwisp2_python_packages: "{{ openwisp2_python_packages + [item] }}" @@ -146,6 +153,20 @@ register: result until: result is success +- name: Install openwisp2_radius and its dependencies + when: openwisp2_radius + pip: + name: "openwisp-radius~={{ openwisp2_radius_version }}" + state: latest + virtualenv: "{{ virtualenv_path }}" + virtualenv_python: "{{ openwisp2_python }}" + virtualenv_site_packages: yes + notify: reload supervisor + retries: 5 + delay: 10 + register: result + until: result is success + - name: Install extra python packages pip: name: "{{ openwisp2_extra_python_packages }}" diff --git a/templates/freeradius/clients.conf.j2 b/templates/freeradius/clients.conf.j2 new file mode 100644 index 00000000..91d48f41 --- /dev/null +++ b/templates/freeradius/clients.conf.j2 @@ -0,0 +1,7 @@ +# Freeradius Clients + +client radius_clients { + ipaddr = {{ freeradius_clients_ip }} + secret = {{ freeradius_clients_key }} + nas_type = other +} diff --git a/templates/freeradius/openwisp_site.j2 b/templates/freeradius/openwisp_site.j2 new file mode 100644 index 00000000..0e8f50d4 --- /dev/null +++ b/templates/freeradius/openwisp_site.j2 @@ -0,0 +1,53 @@ +server default { + listen { + type = auth + ipaddr = * + port = 0 + limit { + max_connections = 16 + lifetime = 0 + idle_timeout = 30 + } + } + + listen { + ipaddr = * + port = 0 + type = acct + limit {} + } + + authorize { + rest + sql + dailycounter + noresetcounter + dailybandwidthcounter + } + + authenticate {} + + preacct { + preprocess + acct_unique + suffix + files + } + + accounting { + rest + } + + session {} + + post-auth { + rest + + Post-Auth-Type REJECT { + rest + } + } + + pre-proxy {} + post-proxy {} +} diff --git a/templates/freeradius/radiusd.conf.j2 b/templates/freeradius/radiusd.conf.j2 new file mode 100644 index 00000000..8db7f031 --- /dev/null +++ b/templates/freeradius/radiusd.conf.j2 @@ -0,0 +1,63 @@ +prefix = /usr +exec_prefix = ${prefix} +sysconfdir = /etc +localstatedir = /var +sbindir = ${exec_prefix}/sbin +logdir = /var/log/radius +raddbdir = ${sysconfdir}/raddb +radacctdir = /var/log/radius/radacct +name = radiusd +confdir = ${raddbdir} +modconfdir = ${confdir}/mods-config +certdir = ${confdir}/certs +cadir = ${confdir}/certs +run_dir = ${localstatedir}/run/${name} +db_dir = ${raddbdir} +libdir = /usr/lib/freeradius +pidfile = ${run_dir}/${name}.pid +correct_escapes = true +max_request_time = 30 +cleanup_delay = 5 +max_requests = 16384 +hostname_lookups = no + +log { + destination = stdout + auth = yes + auth_badpass = yes + auth_goodpass = yes +} + +checkrad = ${sbindir}/checkrad +security { + user = root + group = root + allow_core_dumps = no + max_attributes = 200 + reject_delay = 1 + status_server = yes + allow_vulnerable_openssl = no +} + +proxy_requests = yes +$INCLUDE proxy.conf +$INCLUDE clients.conf +thread pool { + start_servers = 5 + max_servers = 32 + min_spare_servers = 3 + max_spare_servers = 10 + max_requests_per_server = 0 + auto_limit_acct = no +} + +modules { + $INCLUDE mods-enabled/ +} + +instantiate {} + +policy { + $INCLUDE policy.d/ +} +$INCLUDE sites-enabled/ diff --git a/templates/freeradius/rest.j2 b/templates/freeradius/rest.j2 new file mode 100644 index 00000000..94af8f73 --- /dev/null +++ b/templates/freeradius/rest.j2 @@ -0,0 +1,31 @@ +rest { + tls = {} + connect_uri = "{{ freeradius_rest.url }}" + + authorize { + uri = "${..connect_uri}/authorize/" + method = 'post' + body = 'json' + data = '{"username": "%{User-Name}", "password": "%{User-Password}"}' + tls = ${..tls} + } + + # this section can be left empty + authenticate {} + + post-auth { + uri = "${..connect_uri}/postauth/" + method = 'post' + body = 'json' + data = '{"username": "%{User-Name}", "password": "%{User-Password}", "reply": "%{reply:Packet-Type}", "called_station_id": "%{Called-Station-ID}", "calling_station_id": "%{Calling-Station-ID}"}' + tls = ${..tls} + } + + accounting { + uri = "${..connect_uri}/accounting/" + method = 'post' + body = 'json' + data = '{"status_type": "%{Acct-Status-Type}", "session_id": "%{Acct-Session-Id}", "unique_id": "%{Acct-Unique-Session-Id}", "username": "%{User-Name}", "realm": "%{Realm}", "nas_ip_address": "%{NAS-IP-Address}", "nas_port_id": "%{NAS-Port}", "nas_port_type": "%{NAS-Port-Type}", "session_time": "%{Acct-Session-Time}", "authentication": "%{Acct-Authentic}", "input_octets": "%{Acct-Input-Octets}", "output_octets": "%{Acct-Output-Octets}", "called_station_id": "%{Called-Station-Id}", "calling_station_id": "%{Calling-Station-Id}", "terminate_cause": "%{Acct-Terminate-Cause}", "service_type": "%{Service-Type}", "framed_protocol": "%{Framed-Protocol}", "framed_ip_address": "%{Framed-IP-Address}"}' + tls = ${..tls} + } +} diff --git a/templates/freeradius/sql.j2 b/templates/freeradius/sql.j2 new file mode 100644 index 00000000..d949ab60 --- /dev/null +++ b/templates/freeradius/sql.j2 @@ -0,0 +1,33 @@ +sql { + driver = "{{ freeradius_sql.driver }}" + dialect = "{{ freeradius_sql.dialect }}" +{% if 'postgresql' == freeradius_sql.dialect %} + radius_db = "host={{ freeradius_sql.host }} port={{ freeradius_sql.port }} dbname={{ freeradius_sql.dbname }} user={{ freeradius_sql.user }} password={{ freeradius_sql.password }}" +{% elif 'sqlite' == freeradius_sql.dialect %} + sqlite { + filename = "{{ openwisp2_database.name }}" + } +{% endif %} + acct_table1 = "radacct" + acct_table2 = "radacct" + postauth_table = "radpostauth" + authcheck_table = "radcheck" + groupcheck_table = "radgroupcheck" + authreply_table = "radreply" + groupreply_table = "radgroupreply" + usergroup_table = "radusergroup" + delete_stale_sessions = yes + client_table = "nas" + group_attribute = "SQL-Group" + $INCLUDE ${modconfdir}/${.:name}/main/${dialect}/queries.conf + pool { + start = ${thread[pool].start_servers} + min = ${thread[pool].min_spare_servers} + max = ${thread[pool].max_servers} + spare = ${thread[pool].max_spare_servers} + uses = 0 + retry_delay = 30 + lifetime = 0 + idle_timeout = 60 + } +} diff --git a/templates/freeradius/sql_counter.j2 b/templates/freeradius/sql_counter.j2 new file mode 100644 index 00000000..e1900013 --- /dev/null +++ b/templates/freeradius/sql_counter.j2 @@ -0,0 +1,41 @@ +# The dailycounter is included by default in the freeradius conf + +sqlcounter dailycounter { + sql_module_instance = sql + dialect = ${modules.sql.dialect} + + counter_name = Daily-Session-Time + check_name = Max-Daily-Session + reply_name = Session-Timeout + + key = User-Name + reset = daily + + $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf +} + +# The noresetcounter is included by default in the freeradius conf +sqlcounter noresetcounter { + sql_module_instance = sql + dialect = ${modules.sql.dialect} + + counter_name = Max-All-Session-Time + check_name = Max-All-Session + key = User-Name + reset = never + + $INCLUDE ${modconfdir}/sql/counter/${dialect}/${.:instance}.conf +} + +# The dailybandwidthcounter is added for django-freeradius +sqlcounter dailybandwidthcounter { + counter_name = Max-Daily-Session-Traffic + check_name = Max-Daily-Session-Traffic + sql_module_instance = sql + key = 'User-Name' + reset = daily + query = "SELECT SUM(acctinputoctets + acctoutputoctets) \ + FROM radacct \ + WHERE UserName='%{${key}}' \ + AND UNIX_TIMESTAMP(acctstarttime) + acctsessiontime > '%%b'" +} diff --git a/templates/openwisp2/settings.py b/templates/openwisp2/settings.py index c3dcd5a1..a1c0de35 100644 --- a/templates/openwisp2/settings.py +++ b/templates/openwisp2/settings.py @@ -1,10 +1,9 @@ import os import sys +from celery.schedules import crontab TESTING = 'test' in sys.argv -from datetime import timedelta - # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -57,6 +56,15 @@ # openwisp2 admin theme # (must be loaded here) 'openwisp_utils.admin_theme', +{% if openwisp2_radius %} + 'django_filters', + 'rest_framework.authtoken', + 'rest_auth', + 'rest_auth.registration', + 'openwisp_radius', + 'private_storage', + 'drf_yasg', +{% endif %} # admin 'django.contrib.admin', 'django.forms', @@ -107,12 +115,28 @@ 'pipeline.middleware.MinifyHTMLMiddleware' ] +{% if openwisp2_radius %} +OPENWISP_RADIUS_FREERADIUS_ALLOWED_HOSTS = {{ openwisp2_freeradius_allowed_hosts }} + +# SMS +REST_AUTH_SERIALIZERS = { + 'PASSWORD_RESET_SERIALIZER': 'openwisp_radius.api.serializers.PasswordResetSerializer', +} +REST_AUTH_REGISTER_SERIALIZERS = { + 'REGISTER_SERIALIZER': 'openwisp_radius.api.serializers.RegisterSerializer', +} +OPENWISP_RADIUS_SMS_TOKEN_MAX_IP_DAILY = {{ openwisp2_radius_sms_token_max_ip_daily }} +SENDSMS_BACKEND = '{{ openwisp2_radius_sms_backend }}' + +OPENWISP_USERS_AUTH_API = {{ openwisp2_users_auth_api }} +{% endif %} + ROOT_URLCONF = 'openwisp2.urls' CHANNEL_LAYERS = { 'default': { - "BACKEND": "channels_redis.core.RedisChannelLayer", - "CONFIG": {"hosts": [('localhost', 6379)]}, + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': {'hosts': [('localhost', 6379)]}, }, } ASGI_APPLICATION = 'openwisp2.routing.application' @@ -160,25 +184,55 @@ CELERY_BEAT_SCHEDULE = { 'delete_old_notifications': { 'task': 'openwisp_notifications.tasks.delete_old_notifications', - 'schedule': timedelta(days=1), - 'args': ({{ openwisp2_notifications_delete_old_notifications }},), + 'schedule': crontab(**{ {{ cron_delete_old_notifications }} }), + 'args': (90,), + }, + 'deactivate_expired_users': { + 'task': 'openwisp_radius.tasks.cleanup_stale_radacct', + 'schedule': crontab(**{ {{ cron_deactivate_expired_users }} }), + 'args': None, + 'relative': True, + }, + 'delete_old_users': { + 'task': 'openwisp_radius.tasks.delete_old_users', + 'schedule': crontab(**{ {{ cron_delete_old_users }} }), + 'args': [365], + 'relative': True, + }, + 'cleanup_stale_radacct': { + 'task': 'openwisp_radius.tasks.cleanup_stale_radacct', + 'schedule': crontab(**{ {{ cron_cleanup_stale_radacct }} }), + 'args': [365], + 'relative': True, + }, + 'delete_old_postauth': { + 'task': 'openwisp_radius.tasks.delete_old_postauth', + 'schedule': crontab(**{ {{ cron_delete_old_postauth }} }), + 'args': [365], + 'relative': True, + }, + 'delete_old_radacct': { + 'task': 'openwisp_radius.tasks.delete_old_radacct', + 'schedule': crontab(**{ {{ cron_delete_old_radacct }} }), + 'args': [365], + 'relative': True, }, } # FOR DJANGO REDIS CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": "{{ openwisp2_redis_cache_url }}", - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", + 'default': { + 'BACKEND': 'django_redis.cache.RedisCache', + 'LOCATION': '{{ openwisp2_redis_cache_url }}', + 'OPTIONS': { + 'CLIENT_CLASS': 'django_redis.client.DefaultClient', } } } -SESSION_ENGINE = "django.contrib.sessions.backends.cache" -SESSION_CACHE_ALIAS = "default" +SESSION_ENGINE = 'django.contrib.sessions.backends.cache' +SESSION_CACHE_ALIAS = 'default' SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True @@ -237,8 +291,9 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.9/howto/static-files/ -STATIC_ROOT = '%s/static' % BASE_DIR -MEDIA_ROOT = '%s/media' % BASE_DIR +STATIC_ROOT = os.path.join(BASE_DIR, 'static') +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') +PRIVATE_STORAGE_ROOT = os.path.join(MEDIA_ROOT, 'private') STATIC_URL = '/static/' MEDIA_URL = '/media/' @@ -332,7 +387,7 @@ # HTML minification with django pipeline PIPELINE = { 'PIPELINE_ENABLED': True } # static files minification and invalidation with django-compress-staticfiles -STATICFILES_STORAGE = 'compress_staticfiles.storage.CompressStaticFilesStorage' +STATICFILES_STORAGE = 'openwisp2.storage.OpenwispCompressStaticFilesStorage' # GZIP compression is handled by nginx BROTLI_STATIC_COMPRESSION = False GZIP_STATIC_COMPRESSION = False diff --git a/templates/openwisp2/storage.py b/templates/openwisp2/storage.py new file mode 100644 index 00000000..c461a68c --- /dev/null +++ b/templates/openwisp2/storage.py @@ -0,0 +1,6 @@ +# Required for openwisp-radius +from compress_staticfiles.storage import CompressStaticFilesStorage + + +class OpenwispCompressStaticFilesStorage(CompressStaticFilesStorage): + manifest_strict = False diff --git a/templates/openwisp2/urls.py b/templates/openwisp2/urls.py index 851384e7..92fec6df 100644 --- a/templates/openwisp2/urls.py +++ b/templates/openwisp2/urls.py @@ -19,6 +19,11 @@ {% if openwisp2_firmware_upgrader %} url(r'^', include('openwisp_firmware_upgrader.urls')), {% endif %} + {% if openwisp2_radius %} + url(r'^', include('openwisp_radius.urls')), + url(r'^api/v1/', include('openwisp_users.api.urls')), + url(r'^api/v1/', include('openwisp_utils.api.urls')), + {% endif %} {% for extra_url in openwisp2_extra_urls %} {{ extra_url }}, {% endfor %}