diff options
author | Christian Poessinger <christian@poessinger.com> | 2020-12-12 14:03:54 +0100 |
---|---|---|
committer | Christian Poessinger <christian@poessinger.com> | 2020-12-28 19:42:50 +0100 |
commit | a8a019c4f318ba6ad2f83b9b4f605de3830c7b28 (patch) | |
tree | 32a2388a9366912167906585b73db2eb92fbfdbd | |
parent | c1fcbba9cb45f981e5bd8decf3ebbc1e17d9fbd9 (diff) | |
download | vyos-1x-a8a019c4f318ba6ad2f83b9b4f605de3830c7b28.tar.gz vyos-1x-a8a019c4f318ba6ad2f83b9b4f605de3830c7b28.zip |
webproxy: T563: migrate from old Perl code to XML and get_config_dict()
Basic proxy functionality is working but the squidguard smoketest still fails
as this is yet not implemented.
-rw-r--r-- | data/templates/squid/squid.conf.tmpl | 128 | ||||
-rw-r--r-- | debian/control | 3 | ||||
-rw-r--r-- | interface-definitions/service-webproxy.xml.in | 533 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_service_webproxy.py | 7 | ||||
-rwxr-xr-x | src/conf_mode/service_webproxy.py | 128 |
5 files changed, 796 insertions, 3 deletions
diff --git a/data/templates/squid/squid.conf.tmpl b/data/templates/squid/squid.conf.tmpl new file mode 100644 index 000000000..1876146dd --- /dev/null +++ b/data/templates/squid/squid.conf.tmpl @@ -0,0 +1,128 @@ +### generated by service_webproxy.py ### + +acl localhost src 127.0.0.1/32 +acl to_localhost dst 127.0.0.0/8 +acl net src all +acl SSL_ports port 443 +acl Safe_ports port 80 # http +acl Safe_ports port 21 # ftp +acl Safe_ports port 443 # https +acl Safe_ports port 873 # rsync +acl Safe_ports port 70 # gopher +acl Safe_ports port 210 # wais +acl Safe_ports port 1025-65535 # unregistered ports +acl Safe_ports port 280 # http-mgmt +acl Safe_ports port 488 # gss-http +acl Safe_ports port 591 # filemaker +acl Safe_ports port 777 # multiling http +acl CONNECT method CONNECT + +{% if authentication is defined and authentication is not none %} +{% if authentication.children is defined and authentication.children is not none %} +auth_param basic children {{ authentication.children }} +{% endif %} +{% if authentication.credentials_ttl is defined and authentication.credentials_ttl is not none %} +auth_param basic credentialsttl {{ authentication.credentials_ttl }} minute +{% endif %} +{% if authentication.realm is defined and authentication.realm is not none %} +auth_param basic realm "{{ authentication.realm }}" +{% endif %} +{# LDAP based Authentication #} +{% if authentication.method is defined and authentication.method is not none %} +{% if authentication.ldap is defined and authentication.ldap is not none and authentication.method == 'ldap' %} +auth_param basic program /usr/lib/squid/basic_ldap_auth -v {{ authentication.ldap.version }} -b "{{ authentication.ldap.base_dn }}" {{ '-D "' + authentication.ldap.bind_dn + '"' if authentication.ldap.bind_dn is defined }} {{ '-w "' + authentication.ldap.password + '"' if authentication.ldap.password is defined }} {{ '-f "' + authentication.ldap.filter_expression + '"' if authentication.ldap.filter_expression is defined }} {{ '-u "' + authentication.ldap.username_attribute + '"' if authentication.ldap.username_attribute is defined }} -p {{ authentication.ldap.port }} {{ '-ZZ' if authentication.ldap.use_ssl is defined }} -R -h "{{ authentication.ldap.server }}" +{% endif %} +acl auth proxy_auth REQUIRED +http_access allow auth +{% endif %} +{% endif %} + +http_access allow manager localhost +http_access deny manager +http_access deny !Safe_ports +http_access deny CONNECT !SSL_ports +http_access allow localhost +http_access allow net +http_access deny all + +{% if reply_block_mime is defined and reply_block_mime is not none %} +{% for mime_type in reply_block_mime %} +acl BLOCK_MIME rep_mime_type {{ mime_type }} +{% endfor %} +http_reply_access deny BLOCK_MIME +{% endif %} + +{% if cache_size is defined and cache_size is not none %} +{% if cache_size | int > 0 %} +cache_dir ufs /var/spool/squid {{ cache_size }} 16 256 +{% else %} +# disabling disk cache +{% endif %} +{% endif %} +{% if mem_cache_size is defined and mem_cache_size is not none %} +cache_mem {{ mem_cache_size }} MB +{% endif %} +{% if disable_access_log is defined %} +access_log none +{% else %} +access_log /var/log/squid/access.log squid +{% endif %} + +{# by default we'll disable the store log #} +cache_store_log none + +{% if append_domain is defined and append_domain is not none %} +append_domain {{ append_domain }} +{% endif %} +{% if maximum_object_size is defined and maximum_object_size is not none %} +maximum_object_size {{ maximum_object_size }} KB +{% endif %} +{% if minimum_object_size is defined and minimum_object_size is not none %} +minimum_object_size {{ minimum_object_size }} KB +{% endif %} +{% if reply_body_max_size is defined and reply_body_max_size is not none %} +reply_body_max_size {{ reply_body_max_size }} KB +{% endif %} +{% if outgoing_address is defined and outgoing_address is not none %} +tcp_outgoing_address {{ outgoing_address }} +{% endif %} + + +{% if listen_address is defined and listen_address is not none %} +{% for address, config in listen_address.items() %} +http_port {{ address }}:{{ config.port if config.port is defined else default_port }} {{ 'intercept' if config.disable_transparent is not defined }} +{% endfor %} +{% endif %} +http_port 127.0.0.1:{{ default_port }} + +{# NOT insert the client address in X-Forwarded-For header #} +forwarded_for off + +{% if cache_peer is defined and cache_peer is not none %} +{% for peer, config in cache_peer.items() %} +{% if not 'type' in webproxy['cache-peer'][peer] %} +{% set p_type = "parent" %} +{% else %} +{% set p_type = webproxy['cache-peer'][peer]['type'] %} +{% endif %} + +{% if not 'http-port' in webproxy['cache-peer'][peer] %} +{% set p_http_port = 3128 %} +{% else %} +{% set p_http_port = webproxy['cache-peer'][peer]['http-port'] %} +{% endif %} + +{% if not 'icp-port' in webproxy['cache-peer'][peer] %} +{% set p_icp_port = 0 %} +{% else %} +{% set p_icp_port = webproxy['cache-peer'][peer]['icp-port'] %} +{% endif %} + +{% if not 'options' in webproxy['cache-peer'][peer] %} +{% set p_options = "no-query default" %} +{% else %} +{% set p_options = webproxy['cache-peer'][peer]['options'] %} +{% endif %} +cache_peer {{ config.address }} {{p_type}} {{p_http_port}} {{p_icp_port}} {{p_options}} +{% endfor %} +{% endif %} diff --git a/debian/control b/debian/control index dc5094e8e..ccdaa8492 100644 --- a/debian/control +++ b/debian/control @@ -108,6 +108,9 @@ Depends: salt-minion, snmp, snmpd, + squid, + squidclient, + squidguard, ssl-cert, systemd, tcpdump, diff --git a/interface-definitions/service-webproxy.xml.in b/interface-definitions/service-webproxy.xml.in new file mode 100644 index 000000000..5a329af78 --- /dev/null +++ b/interface-definitions/service-webproxy.xml.in @@ -0,0 +1,533 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="service"> + <children> + <node name="webproxy" owner="${vyos_conf_scripts_dir}/service_webproxy.py"> + <properties> + <help>Webproxy service settings</help> + <priority>500</priority> + </properties> + <children> + <leafNode name="append-domain"> + <properties> + <help>Default domain name</help> + <valueHelp> + <format>domain</format> + <description>Domain to use for urls that do not contain a '.'</description> + </valueHelp> + <constraint> + <regex>^[\.][a-z0-9-][$]?</regex> + </constraint> + <constraintErrorMessage>Must start append-domain with a '.'</constraintErrorMessage> + </properties> + </leafNode> + <node name="authentication"> + <properties> + <help>Proxy Authentication Settings</help> + </properties> + <children> + <leafNode name="children"> + <properties> + <help>Number of authentication helper processes (default: 5)</help> + <valueHelp> + <format>n</format> + <description>Number of authentication helper processes</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-500"/> + </constraint> + </properties> + <defaultValue>5</defaultValue> + </leafNode> + <leafNode name="credentials-ttl"> + <properties> + <help>Authenticated session time to live in minutes (default: 60)</help> + <valueHelp> + <format>n</format> + <description>Authenticated session timeout</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-600"/> + </constraint> + </properties> + <defaultValue>60</defaultValue> + </leafNode> + <node name="ldap"> + <properties> + <help>LDAP authentication settings</help> + </properties> + <children> + <leafNode name="base-dn"> + <properties> + <help>LDAP Base DN to search</help> + </properties> + </leafNode> + <leafNode name="bind-dn"> + <properties> + <help>LDAP DN used to bind to server</help> + </properties> + </leafNode> + <leafNode name="filter-expression"> + <properties> + <help>Filter expression to perform LDAP search with</help> + </properties> + </leafNode> + <leafNode name="password"> + <properties> + <help>LDAP password to bind with</help> + </properties> + </leafNode> + <leafNode name="persistent-connection"> + <properties> + <help>Use persistent LDAP connection</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="port"> + <properties> + <help>LDAP server port to use (default: 389)</help> + <valueHelp> + <format>u32:1-65535</format> + <description>Port number to use</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-65535"/> + </constraint> + </properties> + <defaultValue>389</defaultValue> + </leafNode> + <leafNode name="server"> + <properties> + <help>LDAP server to use</help> + </properties> + </leafNode> + <leafNode name="use-ssl"> + <properties> + <help>Use SSL/TLS for LDAP connection</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="username-attribute"> + <properties> + <help>LDAP username attribute</help> + </properties> + </leafNode> + <leafNode name="version"> + <properties> + <help>LDAP protocol version (default: 3)</help> + <completionHelp> + <list>2 3</list> + </completionHelp> + <valueHelp> + <format>2</format> + <description>LDAP protocol version 2</description> + </valueHelp> + <valueHelp> + <format>3</format> + <description>LDAP protocol version 2</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 2-3"/> + </constraint> + </properties> + <defaultValue>3</defaultValue> + </leafNode> + </children> + </node> + <leafNode name="method"> + <properties> + <help>Authentication Method</help> + <completionHelp> + <list>ldap</list> + </completionHelp> + <valueHelp> + <format>ldap</format> + <description>Lightweight Directory Access Protocol</description> + </valueHelp> + <constraint> + <regex>^(ldap)$</regex> + </constraint> + <constraintErrorMessage>The only supported method currently is LDAP</constraintErrorMessage> + </properties> + </leafNode> + <leafNode name="realm"> + <properties> + <help>Name of authentication realm (e.g. "My Company proxy server")</help> + </properties> + </leafNode> + </children> + </node> + + <tagNode name="cache-peer"> + <properties> + <help>cache-peer hostname</help> + <valueHelp> + <format>hostname</format> + <description>Cache peers FQDN</description> + </valueHelp> + </properties> + <children> + <leafNode name="address"> + <properties> + <help>IPv4 address of peer-cache</help> + <valueHelp> + <format>ipv4</format> + <description>IPv4 address of the cache peer</description> + </valueHelp> + </properties> + </leafNode> + <leafNode name="http-port"> + <properties> + <help>Cache peer http port (default 3128)</help> + <valueHelp> + <format>1-65535</format> + <description>Cache peer http port (default 3128)</description> + </valueHelp> + </properties> + </leafNode> + <leafNode name="icp-port"> + <properties> + <help>Cache peer icp port (default disabled)</help> + <valueHelp> + <format>1-65535</format> + <description>Cache peer icp port (default disabled)</description> + </valueHelp> + </properties> + </leafNode> + <leafNode name="options"> + <properties> + <help>Cache peer options</help> + <valueHelp> + <format>text</format> + <description>Cache peer options</description> + </valueHelp> + </properties> + </leafNode> + <leafNode name="type"> + <properties> + <help>Squid peer type (default parent)</help> + <completionHelp> + <list>parent sibling multicast</list> + </completionHelp> + <valueHelp> + <format>parent</format> + <description>Peer is a parent</description> + </valueHelp> + <valueHelp> + <format>sibling</format> + <description>Peer is a sibling</description> + </valueHelp> + <valueHelp> + <format>multicast</format> + <description>Peer is a member of a multicast group</description> + </valueHelp> + <constraint> + <regex>^(parent|sibling|multicast)$</regex> + </constraint> + </properties> + </leafNode> + </children> + </tagNode> + <leafNode name="cache-size"> + <properties> + <help>Disk cache size in MB (default: 100)</help> + <valueHelp> + <format>u32</format> + <description>Disk cache size in MB</description> + </valueHelp> + <valueHelp> + <format>0</format> + <description>Disable disk caching</description> + </valueHelp> + </properties> + <defaultValue>100</defaultValue> + </leafNode> + <leafNode name="default-port"> + <properties> + <help>Default Proxy Port (default: 3128)</help> + <valueHelp> + <format>u32:1025-65535</format> + <description>Default port number</description> + </valueHelp> + </properties> + <defaultValue>3128</defaultValue> + </leafNode> + <leafNode name="disable-access-log"> + <properties> + <help>Disable logging of HTTP accesses</help> + <valueless/> + </properties> + </leafNode> + <leafNode name="domain-block"> + <properties> + <help>Domain name to block</help> + <multi/> + </properties> + </leafNode> + <leafNode name="domain-noncache"> + <properties> + <help>Domain name to access without caching</help> + <multi/> + </properties> + </leafNode> + <tagNode name="listen-address"> + <properties> + <help>IPv4 address for webproxy to listen on [REQUIRED]</help> + <valueHelp> + <format>ipv4</format> + <description>IPv4 address listen on</description> + </valueHelp> + </properties> + <children> + <leafNode name="port"> + <properties> + <help>Default Proxy Port (default: 3128)</help> + <valueHelp> + <format>u32:1025-65535</format> + <description>Default port number</description> + </valueHelp> + </properties> + </leafNode> + <leafNode name="disable-transparent"> + <properties> + <help>Disable transparent mode</help> + <valueless/> + </properties> + </leafNode> + </children> + </tagNode> + <leafNode name="maximum-object-size"> + <properties> + <help>Maximum size of object to be stored in cache in kilobytes</help> + <valueHelp> + <format>u32</format> + <description>Object size in KB</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-100000"/> + </constraint> + </properties> + </leafNode> + <leafNode name="mem-cache-size"> + <properties> + <help>Memory cache size in MB</help> + <valueHelp> + <format>u32</format> + <description>Memory cache size in MB </description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-100000"/> + </constraint> + </properties> + <defaultValue>20</defaultValue> + </leafNode> + <leafNode name="minimum-object-size"> + <properties> + <help>Maximum size of object to be stored in cache in kilobytes</help> + <valueHelp> + <format>u32</format> + <description>Object size in KB</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-100000"/> + </constraint> + </properties> + </leafNode> + <leafNode name="outgoing-address"> + <properties> + <help>Outgoing IP address for webproxy</help> + </properties> + </leafNode> + <leafNode name="reply-block-mime"> + <properties> + <help>MIME type to block</help> + <completionHelp> + <list>image/gif www/mime application/macbinary application/oda application/octet-stream application/pdf application/postscript application/postscript application/postscript text/rtf application/octet-stream application/octet-stream application/x-tar application/x-csh application/x-dvi application/x-hdf application/x-latex text/plain application/x-netcdf application/x-netcdf application/x-sh application/x-tcl application/x-tex application/x-texinfo application/x-texinfo application/x-troff application/x-troff application/x-troff application/x-troff-man application/x-troff-me application/x-troff-ms application/x-wais-source application/zip application/x-bcpio application/x-cpio application/x-gtar application/x-rpm application/x-shar application/x-sv4cpio application/x-sv4crc application/x-tar application/x-ustar audio/basic audio/basic audio/mpeg audio/mpeg audio/mpeg audio/x-aiff audio/x-aiff audio/x-aiff audio/x-wav image/bmp image/ief image/jpeg image/jpeg image/jpeg image/tiff image/tiff image/x-cmu-raster image/x-portable-anymap image/x-portable-bitmap image/x-portable-graymap image/x-portable-pixmap image/x-rgb image/x-xbitmap image/x-xpixmap image/x-xwindowdump text/html text/html text/css application/x-javascript text/plain text/plain text/plain text/plain text/plain text/plain text/plain text/plain text/plain text/richtext text/tab-separated-values text/x-setext video/mpeg video/mpeg video/mpeg video/quicktime video/quicktime video/x-msvideo video/x-sgi-movie application/mac-compactpro application/mac-binhex40 application/macwriteii application/msword application/msword application/vnd.ms-excel application/vnd.ms-powerpoint application/vnd.lotus-1-2-3 application/vnd.mif application/x-stuffit application/pict application/pict application/x-arj-compressed application/x-lha-compressed application/x-lha-compressed application/x-deflate text/plain application/octet-stream application/octet-stream image/png application/octet-stream application/x-xpinstall application/octet-stream text/plain application/x-director application/x-director application/x-director image/vnd.djvu image/vnd.djvu application/octet-stream application/octet-stream application/andrew-inset x-conference/x-cooltalk model/iges model/iges audio/midi audio/midi audio/midi model/mesh model/mesh video/vnd.mpegurl chemical/x-pdb application/x-chess-pgn audio/x-realaudio audio/x-pn-realaudio audio/x-pn-realaudio text/sgml text/sgml application/x-koan application/x-koan application/x-koan application/x-koan application/smil application/smil application/octet-stream application/x-futuresplash application/x-shockwave-flash application/x-cdlink model/vrml image/vnd.wap.wbmp application/vnd.wap.wbxml application/vnd.wap.wmlc application/vnd.wap.wmlscriptc application/vnd.wap.wmlscript application/xhtml application/xhtml text/xml text/xml chemical/x-xyz text/plain</list> + </completionHelp> + <constraint> + <regex>^(image/gif|www/mime|application/macbinary|application/oda|application/octet-stream|application/pdf|application/postscript|application/postscript|application/postscript|text/rtf|application/octet-stream|application/octet-stream|application/x-tar|application/x-csh|application/x-dvi|application/x-hdf|application/x-latex|text/plain|application/x-netcdf|application/x-netcdf|application/x-sh|application/x-tcl|application/x-tex|application/x-texinfo|application/x-texinfo|application/x-troff|application/x-troff|application/x-troff|application/x-troff-man|application/x-troff-me|application/x-troff-ms|application/x-wais-source|application/zip|application/x-bcpio|application/x-cpio|application/x-gtar|application/x-rpm|application/x-shar|application/x-sv4cpio|application/x-sv4crc|application/x-tar|application/x-ustar|audio/basic|audio/basic|audio/mpeg|audio/mpeg|audio/mpeg|audio/x-aiff|audio/x-aiff|audio/x-aiff|audio/x-wav|image/bmp|image/ief|image/jpeg|image/jpeg|image/jpeg|image/tiff|image/tiff|image/x-cmu-raster|image/x-portable-anymap|image/x-portable-bitmap|image/x-portable-graymap|image/x-portable-pixmap|image/x-rgb|image/x-xbitmap|image/x-xpixmap|image/x-xwindowdump|text/html|text/html|text/css|application/x-javascript|text/plain|text/plain|text/plain|text/plain|text/plain|text/plain|text/plain|text/plain|text/plain|text/richtext|text/tab-separated-values|text/x-setext|video/mpeg|video/mpeg|video/mpeg|video/quicktime|video/quicktime|video/x-msvideo|video/x-sgi-movie|application/mac-compactpro|application/mac-binhex40|application/macwriteii|application/msword|application/msword|application/vnd.ms-excel|application/vnd.ms-powerpoint|application/vnd.lotus-1-2-3|application/vnd.mif|application/x-stuffit|application/pict|application/pict|application/x-arj-compressed|application/x-lha-compressed|application/x-lha-compressed|application/x-deflate|text/plain|application/octet-stream|application/octet-stream|image/png|application/octet-stream|application/x-xpinstall|application/octet-stream|text/plain|application/x-director|application/x-director|application/x-director|image/vnd.djvu|image/vnd.djvu|application/octet-stream|application/octet-stream|application/andrew-inset|x-conference/x-cooltalk|model/iges|model/iges|audio/midi|audio/midi|audio/midi|model/mesh|model/mesh|video/vnd.mpegurl|chemical/x-pdb|application/x-chess-pgn|audio/x-realaudio|audio/x-pn-realaudio|audio/x-pn-realaudio|text/sgml|text/sgml|application/x-koan|application/x-koan|application/x-koan|application/x-koan|application/smil|application/smil|application/octet-stream|application/x-futuresplash|application/x-shockwave-flash|application/x-cdlink|model/vrml|image/vnd.wap.wbmp|application/vnd.wap.wbxml|application/vnd.wap.wmlc|application/vnd.wap.wmlscriptc|application/vnd.wap.wmlscript|application/xhtml|application/xhtml|text/xml|text/xml|chemical/x-xyz|text/plain)$</regex> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="reply-body-max-size"> + <properties> + <help>Maximum reply body size in KB</help> + <valueHelp> + <format>u32</format> + <description>Reply size in KB</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-100000"/> + </constraint> + </properties> + </leafNode> + <node name="url-filtering"> + <properties> + <help>URL filtering settings</help> + </properties> + <children> + <leafNode name="disable"> + <properties> + <help>Disable URL filtering</help> + <valueless/> + </properties> + </leafNode> + <node name="squidguard"> + <properties> + <help>URL filtering via squidGuard redirector</help> + </properties> + <children> + <leafNode name="allow-category"> + <properties> + <help>Category to allow</help> + <multi/> + </properties> + </leafNode> + <leafNode name="allow-ipaddr-url"> + <properties> + <help>Allow IP address URLs</help> + <valueless/> + </properties> + </leafNode> + <node name="auto-update"> + <properties> + <help>Auto update settings</help> + </properties> + <children> + <leafNode name="update-hour"> + <properties> + <help>Hour of day for database update [REQUIRED]</help> + <valueHelp> + <format>u32:0-23</format> + <description>Hour for database update</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-23"/> + </constraint> + </properties> + <defaultValue>0</defaultValue> + </leafNode> + </children> + </node> + <leafNode name="block-category"> + <properties> + <help>Category to block</help> + <multi/> + </properties> + </leafNode> + <leafNode name="default-action"> + <properties> + <help>Default action</help> + <completionHelp> + <list>allow block</list> + </completionHelp> + <valueHelp> + <format>allow</format> + <description>Default filter action to allow (default)</description> + </valueHelp> + <valueHelp> + <format>block</format> + <description>Default filter action to allow (default)</description> + </valueHelp> + <constraint> + <regex>^(allow|block)$</regex> + </constraint> + </properties> + </leafNode> + <leafNode name="enable-safe-search"> + <properties> + <help>Enable safe-mode search on popular search engines</help> + </properties> + </leafNode> + <leafNode name="local-block-keyword"> + <properties> + <help>Local keyword to block</help> + <valueHelp> + <format>keyword</format> + <description>Keyword (or regex) to block</description> + </valueHelp> + <multi/> + </properties> + </leafNode> + <leafNode name="local-block-url"> + <properties> + <help>Local URL to block</help> + <valueHelp> + <format>url</format> + <description>Local URL to block (without http:\/\/</description> + </valueHelp> + <constraint> + <regex>^(https?:\/\/)$</regex> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="local-block"> + <properties> + <help>Local site to block</help> + <valueHelp> + <format>ipv4</format> + <description>IP address of site to block</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="local-ok-url"> + <properties> + <help>Local URL to allow</help> + <valueHelp> + <format>url</format> + <description>Local URL to allow (without http:\/\/</description> + </valueHelp> + <constraint> + <regex>^(https?:\/\/)$</regex> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="local-ok"> + <properties> + <help>Local site to allow</help> + <valueHelp> + <format>ipv4</format> + <description>IP address of site to allow</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + <leafNode name="log"> + <properties> + <help>Log block category</help> + <completionHelp> + <list>all</list> + </completionHelp> + <multi/> + </properties> + </leafNode> + <leafNode name="redirect-url"> + <properties> + <help>Redirect URL for filtered websites (default: http:\/\/block.vyos.net)</help> + <valueHelp> + <format>url</format> + <description>URL for redirect</description> + </valueHelp> + </properties> + <defaultValue>http:\/\/block.vyos.net</defaultValue> + </leafNode> + <!-- not completed --> + </children> + </node> + </children> + </node> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/smoketest/scripts/cli/test_service_webproxy.py b/smoketest/scripts/cli/test_service_webproxy.py index dac5aa0dd..6f88a351d 100755 --- a/smoketest/scripts/cli/test_service_webproxy.py +++ b/smoketest/scripts/cli/test_service_webproxy.py @@ -127,7 +127,7 @@ class TestServiceWebProxy(unittest.TestCase): realm = 'VyOS Webproxy' ldap_base_dn = 'DC=vyos,DC=net' ldap_server = 'ldap.vyos.net' - ldap_bind_dn = 'CN=proxyuser,CN=Users,DC=example,DC=local' + ldap_bind_dn = f'CN=proxyuser,CN=Users,{ldap_base_dn}' ldap_password = 'VyOS12345' ldap_attr = 'cn' ldap_filter = '(cn=%s)' @@ -156,6 +156,7 @@ class TestServiceWebProxy(unittest.TestCase): self.session.set(base_path + ['authentication', 'ldap', 'username-attribute', ldap_attr]) self.session.set(base_path + ['authentication', 'ldap', 'filter-expression', ldap_filter]) + self.session.set(base_path + ['authentication', 'ldap', 'use-ssl']) # commit changes self.session.commit() @@ -166,8 +167,8 @@ class TestServiceWebProxy(unittest.TestCase): # Now verify LDAP settings self.assertIn(f'auth_param basic children {auth_children}', config) self.assertIn(f'auth_param basic credentialsttl {cred_ttl} minute', config) - self.assertIn(f'auth_param basic realm {realm}', config) - self.assertIn(f'auth_param basic program /usr/lib/squid/basic_ldap_auth -v 3 -b "{ldap_base_dn}" -D "{ldap_bind_dn}" -w {ldap_password} -f {ldap_filter} -u {ldap_attr} -p 389 -R -h {ldap_server}', config) + self.assertIn(f'auth_param basic realm "{realm}"', config) + self.assertIn(f'auth_param basic program /usr/lib/squid/basic_ldap_auth -v 3 -b "{ldap_base_dn}" -D "{ldap_bind_dn}" -w "{ldap_password}" -f "{ldap_filter}" -u "{ldap_attr}" -p 389 -ZZ -R -h "{ldap_server}"', config) self.assertIn(f'acl auth proxy_auth REQUIRED', config) # Check for running process diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py new file mode 100755 index 000000000..128393e51 --- /dev/null +++ b/src/conf_mode/service_webproxy.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 VyOS maintainers and contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 or later as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.template import render +from vyos.util import call +from vyos.util import dict_search +from vyos.validate import is_addr_assigned +from vyos.xml import defaults +from vyos import ConfigError +from vyos import airbag +airbag.enable() + +config_file = '/etc/squid/squid.conf' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['service', 'webproxy'] + if not conf.exists(base): + return None + + proxy = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + # if no authentication method is supplid, no need to add defaults + if not dict_search('authentication.method', proxy): + default_values.pop('authentication') + proxy = dict_merge(default_values, proxy) + + import pprint + pprint.pprint(proxy) + return proxy + + +def verify(proxy): + if not proxy: + return None + + if 'listen_address' not in proxy: + raise ConfigError('listen-address needs to be configured!') + + ldap_auth = dict_search('authentication.method', proxy) == 'ldap' + + for address, config in proxy['listen_address'].items(): + if not is_addr_assigned(address): + raise ConfigError( + f'listen-address "{address}" not assigned on any interface!') + if ldap_auth and 'disable_transparent' not in config: + raise ConfigError('Authentication can not be configured when ' \ + 'proxy is in transparent mode') + + if 'outgoing_address' in proxy: + address = proxy['outgoing_address'] + if not is_addr_assigned(address): + raise ConfigError( + f'outgoing-address "{address}" not assigned on any interface!') + + if 'authentication' in proxy: + if 'method' not in proxy['authentication']: + raise ConfigError('proxy authentication method required!') + + if ldap_auth: + ldap_config = proxy['authentication']['ldap'] + + if 'server' not in ldap_config: + raise ConfigError( + 'LDAP authentication enabled, but no server set') + + if 'password' in ldap_config and 'bind_dn' not in ldap_config: + raise ConfigError( + 'LDAP password can not be set when base-dn is undefined!') + + if 'bind_dn' in ldap_config and 'password' not in ldap_config: + raise ConfigError( + 'LDAP bind DN can not be set without password!') + + if 'base_dn' not in ldap_config: + raise ConfigError('LDAP base-dn must be set!') + +def generate(proxy): + if not proxy: + return None + + render(config_file, 'squid/squid.conf.tmpl', proxy) + return None + +def apply(proxy): + if not proxy: + # proxy is removed in the commit + call('systemctl stop squid.service') + if os.path.exists(config_file): + os.unlink(config_file) + return None + + call('systemctl restart squid.service') + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) |