diff options
47 files changed, 526 insertions, 217 deletions
diff --git a/Vagrantfile b/Vagrantfile index ba5451aa..cb9392e3 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,23 +1,39 @@  # -*- mode: ruby -*-  # vi: set ft=ruby : -Vagrant.configure("2") do |vagrant_config| -  vagrant_config.vm.define :node1 do |config| -    # Please verify the sha512 sum of the downloaded box before importing it into vagrant ! -    # see https://leap.se/en/docs/platform/details/development#Verify.vagrantbox.download -    # for details +Vagrant.configure("2") do |config| +  # Please verify the sha512 sum of the downloaded box before importing it into vagrant ! +  # see https://leap.se/en/docs/platform/details/development#Verify.vagrantbox.download +  # for details + +  config.vm.define :"wheezy", primary: true do |config|      config.vm.box = "LEAP/wheezy" -    #config.vm.network :private_network, ip: "10.5.5.102" +    config.vm.provider "virtualbox" do |v| +      v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] +      v.name = "wheezy" +    end + +    config.vm.provision "puppet" do |puppet| +      puppet.manifests_path = "./vagrant" +      puppet.module_path = "./puppet/modules" +      puppet.manifest_file = "install-platform.pp" +      puppet.options = "--verbose" +    end +    config.vm.provision "shell", path: "vagrant/configure-leap.sh" +    config.ssh.username = "vagrant"      # forward leap_web ports      config.vm.network "forwarded_port", guest: 80,  host:8080      config.vm.network "forwarded_port", guest: 443, host:4443 +  end + +  config.vm.define :"jessie", autostart: false do |config| +    config.vm.box = "LEAP/jessie"      config.vm.provider "virtualbox" do |v| -      v.memory = 1024        v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] -      v.name = "node1" +      v.name = "jessie"      end      config.vm.provision "puppet" do |puppet| @@ -27,8 +43,11 @@ Vagrant.configure("2") do |vagrant_config|        puppet.options = "--verbose"      end      config.vm.provision "shell", path: "vagrant/configure-leap.sh" -      config.ssh.username = "vagrant" +    # forward leap_web ports +    config.vm.network "forwarded_port", guest: 80,  host:8080 +    config.vm.network "forwarded_port", guest: 443, host:4443    end +  end diff --git a/lib/leap_cli/commands/vagrant.rb b/lib/leap_cli/commands/vagrant.rb index e2dfb8a9..bf683cb6 100644 --- a/lib/leap_cli/commands/vagrant.rb +++ b/lib/leap_cli/commands/vagrant.rb @@ -14,7 +14,7 @@ module LeapCli; module Commands            "`config.vm.box` option. The value here should be the name of an installed box or a "+            "shorthand name of a box in HashiCorp's Atlas.",          :arg_name => 'BASEBOX', -        :default_value => 'LEAP/wheezy' +        :default_value => 'LEAP/jessie'        )        start.action do |global_options,options,args|          vagrant_command(["up", "sandbox on"], args, options) @@ -146,7 +146,7 @@ module LeapCli; module Commands      lines = []      netmask = IPAddr.new('255.255.255.255').mask(LeapCli.leapfile.vagrant_network.split('/').last).to_s -    basebox = options[:basebox] || 'LEAP/wheezy' +    basebox = options[:basebox] || 'LEAP/jessie'      if vagrant_version <= Gem::Version.new('1.1.0')        lines << %[Vagrant::Config.run do |config|] diff --git a/puppet/lib/puppet/parser/functions/sorted_yaml.rb b/puppet/lib/puppet/parser/functions/sorted_yaml.rb index fa0db4d2..46cd46ce 100644 --- a/puppet/lib/puppet/parser/functions/sorted_yaml.rb +++ b/puppet/lib/puppet/parser/functions/sorted_yaml.rb @@ -382,7 +382,19 @@ class Ya2YAML  end  module Puppet::Parser::Functions -  newfunction(:sorted_yaml, :type => :rvalue, :doc => "This function outputs yaml, but ensures the keys are sorted.") do |argument| -    return Ya2YAML.new()._ya2yaml(argument) +  newfunction(:sorted_yaml, +    :type => :rvalue, +    :doc => "This function outputs yaml, but ensures the keys are sorted." +    ) do |arguments| + +    if arguments.is_a?(Array) +      if arguments.size != 1 +        raise(Puppet::ParseError, "sorted_yaml(): Wrong number of arguments given (#{arguments.size} for 1)") +      end +      yaml = arguments.first +    else +      yaml = arguments +    end +    return Ya2YAML.new()._ya2yaml(yaml)    end  end diff --git a/puppet/modules/apache b/puppet/modules/apache -Subproject c3e92a9b3cb02f1546b6b1570f10a968d380005 +Subproject 41815f55ec7187a75aec4717c78270593f9776d diff --git a/puppet/modules/couchdb b/puppet/modules/couchdb -Subproject cdde1e172b3ed2c6c1f203341e75bcef5c3c349 +Subproject 016ec71359f6b1b368624c6c94bac2b50979165 diff --git a/puppet/modules/haproxy b/puppet/modules/haproxy -Subproject b398f3cb0a67d1170d0564a3f03977f9a08c2b6 +Subproject af322a73c013f80a958ab7d5d31d0c75cf6d052 diff --git a/puppet/modules/leap_mx/manifests/init.pp b/puppet/modules/leap_mx/manifests/init.pp index 284662d2..5561e326 100644 --- a/puppet/modules/leap_mx/manifests/init.pp +++ b/puppet/modules/leap_mx/manifests/init.pp @@ -41,13 +41,7 @@ class leap_mx {      notify  => Service['leap-mx'];    } -  file { '/etc/default/leap_mx': -    content => 'LOGFILE=/var/log/leap/mx.log', -    owner   => 'root', -    group   => 'root', -    mode    => '0644', -    notify  => Service['leap-mx']; -  } +  leap::logfile { 'mx': }    #    # LEAP-MX CODE AND DEPENDENCIES @@ -75,20 +69,4 @@ class leap_mx {      hasrestart => true,      require    => [ Package['leap-mx'] ];    } - -  augeas { -    'logrotate_mx': -      context => '/files/etc/logrotate.d/leap-mx/rule', -      changes => [ -                  'set file /var/log/leap/mx.log', -                  'set rotate 5', -                  'set schedule daily', -                  'clear nocreate', -                  'rm create', -                  'rm ifempty', -                  'set compress compress', -                  'set missingok missingok', -                  'set copytruncate copytruncate' -                  ] -  }  } diff --git a/puppet/modules/site_apache/manifests/common.pp b/puppet/modules/site_apache/manifests/common.pp index 64beb231..dadf7ea5 100644 --- a/puppet/modules/site_apache/manifests/common.pp +++ b/puppet/modules/site_apache/manifests/common.pp @@ -1,8 +1,26 @@ +# install basic apache modules needed for all services (nagios, webapp)  class site_apache::common { -  include site_apache::module::rewrite +  include apache::module::rewrite +  include apache::module::env    class { '::apache': no_default_site => true, ssl => true } +  # needed for the mod_ssl config +  include apache::module::mime + +  # load mods depending on apache version +  if ( $::lsbdistcodename == 'jessie' ) { +    # apache >= 2.4, debian jessie +    # needed for mod_ssl config +    include apache::module::socache_shmcb +    # generally needed +    include apache::module::mpm_prefork +  } else { +    # apache < 2.4, debian wheezy +    # for "Order" directive, i.e. main apache2.conf +    include apache::module::authz_host +  } +    include site_apache::common::tls  } diff --git a/puppet/modules/site_apache/manifests/module/alias.pp b/puppet/modules/site_apache/manifests/module/alias.pp deleted file mode 100644 index c1f5e185..00000000 --- a/puppet/modules/site_apache/manifests/module/alias.pp +++ /dev/null @@ -1,5 +0,0 @@ -class site_apache::module::alias ( $ensure = present ) -{ - -  apache::module { 'alias': ensure => $ensure } -} diff --git a/puppet/modules/site_apache/manifests/module/expires.pp b/puppet/modules/site_apache/manifests/module/expires.pp deleted file mode 100644 index f73a5607..00000000 --- a/puppet/modules/site_apache/manifests/module/expires.pp +++ /dev/null @@ -1,4 +0,0 @@ -class site_apache::module::expires ( $ensure = present ) -{ -  apache::module { 'expires': ensure => $ensure } -} diff --git a/puppet/modules/site_apache/manifests/module/headers.pp b/puppet/modules/site_apache/manifests/module/headers.pp deleted file mode 100644 index f7caa28c..00000000 --- a/puppet/modules/site_apache/manifests/module/headers.pp +++ /dev/null @@ -1,5 +0,0 @@ -class site_apache::module::headers ( $ensure = present ) -{ - -  apache::module {'headers': ensure => $ensure } -} diff --git a/puppet/modules/site_apache/manifests/module/removeip.pp b/puppet/modules/site_apache/manifests/module/removeip.pp deleted file mode 100644 index f106167a..00000000 --- a/puppet/modules/site_apache/manifests/module/removeip.pp +++ /dev/null @@ -1,5 +0,0 @@ -class site_apache::module::removeip ( $ensure = present ) -{ -  package { 'libapache2-mod-removeip': ensure => $ensure } -  apache::module { 'removeip': ensure => $ensure } -} diff --git a/puppet/modules/site_apache/manifests/module/rewrite.pp b/puppet/modules/site_apache/manifests/module/rewrite.pp deleted file mode 100644 index 7ad00a0c..00000000 --- a/puppet/modules/site_apache/manifests/module/rewrite.pp +++ /dev/null @@ -1,5 +0,0 @@ -class site_apache::module::rewrite ( $ensure = present ) -{ - -  apache::module { 'rewrite': ensure => $ensure } -} diff --git a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb index 0396f54b..9efc6b41 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb @@ -1,14 +1,14 @@  <VirtualHost *:80> -  ServerName <%= api_domain %> +  ServerName <%= @api_domain %>    RewriteEngine On -  RewriteRule ^.*$ https://<%= api_domain -%>:<%= api_port -%>%{REQUEST_URI} [R=permanent,L] +  RewriteRule ^.*$ https://<%= @api_domain -%>:<%= @api_port -%>%{REQUEST_URI} [R=permanent,L]    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common  </VirtualHost> -Listen 0.0.0.0:<%= api_port %> +Listen 0.0.0.0:<%= @api_port %> -<VirtualHost *:<%= api_port -%>> -  ServerName <%= api_domain %> +<VirtualHost *:<%= @api_port -%>> +  ServerName <%= @api_domain %>    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common    SSLCACertificatePath /etc/ssl/certs @@ -27,6 +27,12 @@ Listen 0.0.0.0:<%= api_port %>    </IfModule>    DocumentRoot /srv/leap/webapp/public +  <% if Gem::Version.new(@apache_version) > Gem::Version.new('2.3') %> +  <Directory /srv/leap/webapp/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %>    # Check for maintenance file and redirect all requests    RewriteEngine On diff --git a/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb index 7f9fd5ab..cbb08c30 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb @@ -1,18 +1,18 @@  <VirtualHost *:80> -  ServerName <%= webapp_domain %> -  ServerAlias <%= domain_name %> -  ServerAlias <%= domain %> -  ServerAlias www.<%= domain %> +  ServerName <%= @webapp_domain %> +  ServerAlias <%= @domain_name %> +  ServerAlias <%= @domain %> +  ServerAlias www.<%= @domain %>    RewriteEngine On -  RewriteRule ^.*$ https://<%= webapp_domain -%>%{REQUEST_URI} [R=permanent,L] +  RewriteRule ^.*$ https://<%= @webapp_domain -%>%{REQUEST_URI} [R=permanent,L]    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common  </VirtualHost>  <VirtualHost *:443> -  ServerName <%= webapp_domain %> -  ServerAlias <%= domain_name %> -  ServerAlias <%= domain %> -  ServerAlias www.<%= domain %> +  ServerName <%= @webapp_domain %> +  ServerAlias <%= @domain_name %> +  ServerAlias <%= @domain %> +  ServerAlias www.<%= @domain %>    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common    SSLCACertificatePath /etc/ssl/certs @@ -32,6 +32,12 @@  <% if (defined? @services) and (@services.include? 'webapp') -%>    DocumentRoot /srv/leap/webapp/public +  <% if Gem::Version.new(@apache_version) > Gem::Version.new('2.3') %> +  <Directory /srv/leap/webapp/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %>    RewriteEngine On    # Check for maintenance file and redirect all requests @@ -69,4 +75,3 @@    </DirectoryMatch>  <% end -%>  </VirtualHost> - diff --git a/puppet/modules/site_apt/manifests/init.pp b/puppet/modules/site_apt/manifests/init.pp index cf49f870..635ba975 100644 --- a/puppet/modules/site_apt/manifests/init.pp +++ b/puppet/modules/site_apt/manifests/init.pp @@ -7,11 +7,19 @@ class site_apt {    $apt_url_security  = $apt_config['security']    $apt_url_backports = $apt_config['backports'] +  # needed on jessie hosts for getting pnp4nagios from testing +  if ( $::operatingsystemmajrelease == '8' ) { +    $use_next_release = true +  } else { +    $use_next_release = false +  } +    class { 'apt': -    custom_key_dir => 'puppet:///modules/site_apt/keys', -    debian_url     => $apt_url_basic, -    security_url   => $apt_url_security, -    backports_url  => $apt_url_backports +    custom_key_dir   => 'puppet:///modules/site_apt/keys', +    debian_url       => $apt_url_basic, +    security_url     => $apt_url_security, +    backports_url    => $apt_url_backports, +    use_next_release => $use_next_release    }    # enable http://deb.leap.se debian package repository diff --git a/puppet/modules/site_apt/manifests/leap_repo.pp b/puppet/modules/site_apt/manifests/leap_repo.pp index 2d4ba0e1..462b2686 100644 --- a/puppet/modules/site_apt/manifests/leap_repo.pp +++ b/puppet/modules/site_apt/manifests/leap_repo.pp @@ -1,9 +1,11 @@ +# install leap deb repo together with leap-keyring package +# containing the apt signing key  class site_apt::leap_repo {    $platform = hiera_hash('platform')    $major_version = $platform['major_version']    apt::sources_list { 'leap.list': -    content => "deb http://deb.leap.se/${major_version} wheezy main\n", +    content => "deb http://deb.leap.se/${major_version} ${::lsbdistcodename} main\n",      before  => Exec[refresh_apt]    } diff --git a/puppet/modules/site_apt/manifests/sid_repo.pp b/puppet/modules/site_apt/manifests/sid_repo.pp new file mode 100644 index 00000000..7c1d8783 --- /dev/null +++ b/puppet/modules/site_apt/manifests/sid_repo.pp @@ -0,0 +1,11 @@ +# configure debian unstable aka "sid" +# currently only used for installations that +# use plain couchdb instead of bigcouch +class site_apt::sid_repo { + +  apt::sources_list { 'debian_sid.list': +    content => "deb http://httpredir.debian.org/debian/ sid main\n", +    before  => Exec[refresh_apt] +  } + +} diff --git a/puppet/modules/site_apt/templates/jessie/postfix.seeds b/puppet/modules/site_apt/templates/jessie/postfix.seeds new file mode 100644 index 00000000..1a878ccc --- /dev/null +++ b/puppet/modules/site_apt/templates/jessie/postfix.seeds @@ -0,0 +1 @@ +postfix	postfix/main_mailer_type	select	No configuration diff --git a/puppet/modules/site_apt/templates/secondary.list b/puppet/modules/site_apt/templates/secondary.list index 41334b0b..0c024549 100644 --- a/puppet/modules/site_apt/templates/secondary.list +++ b/puppet/modules/site_apt/templates/secondary.list @@ -1,3 +1,3 @@  # basic -deb http://ftp.debian.org/debian/ <%= lsbdistcodename %> main contrib non-free +deb http://ftp.debian.org/debian/ <%= @lsbdistcodename %> main contrib non-free diff --git a/puppet/modules/site_check_mk/manifests/agent/mx.pp b/puppet/modules/site_check_mk/manifests/agent/mx.pp index 98757b59..20cbcade 100644 --- a/puppet/modules/site_check_mk/manifests/agent/mx.pp +++ b/puppet/modules/site_check_mk/manifests/agent/mx.pp @@ -1,3 +1,4 @@ +# check check_mk agent checks for mx service  class site_check_mk::agent::mx {    # watch logs @@ -6,13 +7,13 @@ class site_check_mk::agent::mx {    }    # local nagios plugin checks via mrpe +  # removed because leap_cli integrates a check for running mx procs already, +  # which is also integrated into nagios (called "Mx/Are_MX_daemons_running")    augeas {      'Leap_MX_Procs':        incl    => '/etc/check_mk/mrpe.cfg',        lens    => 'Spacevars.lns', -      changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Leap_MX_Procs', -        'set Leap_MX_Procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a "/usr/bin/python /usr/bin/twistd --pidfile=/var/run/leap_mx.pid --rundir=/var/lib/leap_mx/ --python=/usr/share/app/leap_mx.tac --logfile=/var/log/leap/mx.log"\'' ], +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Leap_MX_Procs',        require => File['/etc/check_mk/mrpe.cfg'];    } diff --git a/puppet/modules/site_check_mk/manifests/server.pp b/puppet/modules/site_check_mk/manifests/server.pp index 57f68d3e..0159a050 100644 --- a/puppet/modules/site_check_mk/manifests/server.pp +++ b/puppet/modules/site_check_mk/manifests/server.pp @@ -17,6 +17,19 @@ class site_check_mk::server {      ensure => installed,    } +  # we don't use check-mk-multisite, and the jessie version +  # of this config file breaks with apache 2.4 +  # until https://gitlab.com/shared-puppet-modules-group/apache/issues/11 +  # is not fixed, we need to use a generic file type here +  #apache::config::global { 'check-mk-multisite.conf': +  #  ensure => absent +  #} + +  file { '/etc/apache2/conf-enabled/check-mk-multisite.conf': +    ensure  => absent, +    require => Package['check-mk-server']; +  } +    # override paths to use the system check_mk rather than OMD    class { 'check_mk::config':      site              => '', diff --git a/puppet/modules/site_check_mk/templates/use_ssh.mk b/puppet/modules/site_check_mk/templates/use_ssh.mk index 0bebebcf..55269536 100644 --- a/puppet/modules/site_check_mk/templates/use_ssh.mk +++ b/puppet/modules/site_check_mk/templates/use_ssh.mk @@ -1,6 +1,6 @@  # http://mathias-kettner.de/checkmk_datasource_programs.html  datasource_programs = [ -<% nagios_hosts.sort.each do |name,config| %> +<% @nagios_hosts.sort.each do |name,config| %>   ( "ssh -l root -i /etc/check_mk/.ssh/id_rsa -p <%=config['ssh_port']%> <%=config['domain_internal']%> check_mk_agent", [ "<%=config['domain_internal']%>" ], ),<%- end -%>  ] diff --git a/puppet/modules/site_config/manifests/packages/build_essential.pp b/puppet/modules/site_config/manifests/packages/build_essential.pp index 7dfb8b03..8f3b2641 100644 --- a/puppet/modules/site_config/manifests/packages/build_essential.pp +++ b/puppet/modules/site_config/manifests/packages/build_essential.pp @@ -4,8 +4,8 @@  class site_config::packages::build_essential {    if !defined(Package['build-essential']) {      package { -      ['build-essential', 'g++', 'g++-4.7', 'gcc', 'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev']: +      ['build-essential', 'cpp']:          ensure => present      }    } -}
\ No newline at end of file +} diff --git a/puppet/modules/site_config/manifests/remove/files.pp b/puppet/modules/site_config/manifests/remove/files.pp index 466f50c8..67171259 100644 --- a/puppet/modules/site_config/manifests/remove/files.pp +++ b/puppet/modules/site_config/manifests/remove/files.pp @@ -11,6 +11,12 @@  class site_config::remove::files { +  # Platform 0.8 removals +  tidy { +    '/etc/default/leap_mx':; +    '/etc/logrotate.d/leap-mx':; +  } +    #    # Platform 0.7 removals    # @@ -20,13 +26,19 @@ class site_config::remove::files {      '/etc/rsyslog.d/99-leap-mx.conf':;      '/etc/rsyslog.d/01-webapp.conf':;      '/etc/rsyslog.d/50-stunnel.conf':; -    '/etc/logrotate.d/mx':;      '/etc/logrotate.d/stunnel':;      '/var/log/stunnel4/stunnel.log':;      'leap_mx':        path => '/var/log/',        recurse => true,        matches => 'leap_mx*'; +    # We rotate 5 logs, so we should only have mx.log, mx.log.[1-5], with an +    # optional .gz suffix. The following will remove any logs that are out +    # of this range +    'leap_mx_rotate': +      path => '/var/log/leap/', +      recurse => true, +      matches => [ 'mx.log.[6-9](.gz)?', 'mx.log.[0-9][0-9]'];      '/srv/leap/webapp/public/provider.json':;      '/srv/leap/couchdb/designs/tmp_users':        recurse => true, diff --git a/puppet/modules/site_config/manifests/ruby.pp b/puppet/modules/site_config/manifests/ruby.pp index 2a720114..5c13233d 100644 --- a/puppet/modules/site_config/manifests/ruby.pp +++ b/puppet/modules/site_config/manifests/ruby.pp @@ -1,14 +1,8 @@ +# install ruby, rubygems and bundler +# configure ruby settings common to all servers  class site_config::ruby {    Class[Ruby] -> Class[rubygems] -> Class[bundler::install] -  class { '::ruby': ruby_version => '1.9.3' } +  class { '::ruby': }    class { 'bundler::install': install_method => 'package' }    include rubygems  } - - -# -# Ruby settings common to all servers -# -# Why this way? So that other classes can do 'include site_ruby' without creating redeclaration errors. -# See https://puppetlabs.com/blog/modeling-class-composition-with-parameterized-classes/ -# diff --git a/puppet/modules/site_config/manifests/ruby/dev.pp b/puppet/modules/site_config/manifests/ruby/dev.pp index 3ea6ca96..e6eb2f8a 100644 --- a/puppet/modules/site_config/manifests/ruby/dev.pp +++ b/puppet/modules/site_config/manifests/ruby/dev.pp @@ -1,6 +1,6 @@ +# install ruby dev packages needed for building some gems  class site_config::ruby::dev inherits site_config::ruby {    Class['::ruby'] { -    ruby_version => '1.9.3',      install_dev  => true    }    # building gems locally probably requires build-essential and gcc: diff --git a/puppet/modules/site_couchdb/files/designs/identities/Identity.json b/puppet/modules/site_couchdb/files/designs/identities/Identity.json index 2ac092ab..b1c567c1 100644 --- a/puppet/modules/site_couchdb/files/designs/identities/Identity.json +++ b/puppet/modules/site_couchdb/files/designs/identities/Identity.json @@ -2,27 +2,33 @@    "_id": "_design/Identity",    "language": "javascript",    "views": { -    "by_user_id": { -      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['user_id'] != null)) {\n                    emit(doc['user_id'], 1);\n                  }\n                }\n", -      "reduce": "_sum" -    },      "by_address_and_destination": {        "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null) && (doc['destination'] != null)) {\n                    emit([doc['address'], doc['destination']], 1);\n                  }\n                }\n",        "reduce": "_sum"      }, -    "by_address": { -      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null)) {\n                    emit(doc['address'], 1);\n                  }\n                }\n", -      "reduce": "_sum" +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Identity') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }, -    "pgp_key_by_email": { -      "map": "      function(doc) {\n        if (doc.type != 'Identity') {\n          return;\n        }\n        if (typeof doc.keys === \"object\") {\n          emit(doc.address, doc.keys[\"pgp\"]);\n        }\n      }\n" +    "cert_fingerprints_by_expiry": { +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.cert_fingerprints === \"object\") {\n    for (fp in doc.cert_fingerprints) {\n      if (doc.cert_fingerprints.hasOwnProperty(fp)) {\n        emit(doc.cert_fingerprints[fp], fp);\n      }\n    }\n  }\n}\n" +    }, +    "cert_expiry_by_fingerprint": { +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.cert_fingerprints === \"object\") {\n    for (fp in doc.cert_fingerprints) {\n      if (doc.cert_fingerprints.hasOwnProperty(fp)) {\n        emit(fp, doc.cert_fingerprints[fp]);\n      }\n    }\n  }\n}\n"      },      "disabled": { -      "map": "      function(doc) {\n        if (doc.type != 'Identity') {\n          return;\n        }\n        if (typeof doc.user_id === \"undefined\") {\n          emit(doc._id, 1);\n        }\n      }\n" +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.user_id === \"undefined\") {\n    emit(doc._id, 1);\n  }\n}\n"      }, -    "all": { -      "map": "                function(doc) {\n                  if (doc['type'] == 'Identity') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    "pgp_key_by_email": { +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.keys === \"object\") {\n    emit(doc.address, doc.keys[\"pgp\"]);\n  }\n}\n" +    }, +    "by_user_id": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['user_id'] != null)) {\n                    emit(doc['user_id'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_address": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null)) {\n                    emit(doc['address'], 1);\n                  }\n                }\n", +      "reduce": "_sum"      }    }, -  "couchrest-hash": "e9004d70e26770c621a9667536429a68" +  "couchrest-hash": "4a774c3f56122b655a314670403b27e2"  }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/messages/Message.json b/puppet/modules/site_couchdb/files/designs/messages/Message.json index 7bcd74c7..6a48fc4d 100644 --- a/puppet/modules/site_couchdb/files/designs/messages/Message.json +++ b/puppet/modules/site_couchdb/files/designs/messages/Message.json @@ -2,17 +2,17 @@    "_id": "_design/Message",    "language": "javascript",    "views": { -    "by_user_ids_to_show_and_created_at": { -      "map": "// not using at moment\n// call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date])\nfunction (doc) {\n  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n    doc.user_ids_to_show.forEach(function (userId) {\n      emit([userId, doc.created_at], 1);\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" -    },      "by_user_ids_to_show": {        "map": "function (doc) {\n  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n    doc.user_ids_to_show.forEach(function (userId) {\n      emit(userId, 1);\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "by_user_ids_to_show_and_created_at": { +      "map": "// not using at moment\n// call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date])\nfunction (doc) {\n  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n    doc.user_ids_to_show.forEach(function (userId) {\n      emit([userId, doc.created_at], 1);\n    });\n  }\n}\n", +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "all": {        "map": "                function(doc) {\n                  if (doc['type'] == 'Message') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }    }, -  "couchrest-hash": "0967e7cc5bb1e61edc1c085f6f0cecbf" +  "couchrest-hash": "ba80168e51015d2678cad88fc6c5b986"  }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json b/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json index 2c9408b8..578f632b 100644 --- a/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json +++ b/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json @@ -24,27 +24,27 @@      },      "by_includes_post_by_and_is_open_and_created_at": {        "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.is_open, doc.created_at], 1);\n      }\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" -    }, -    "by_includes_post_by_and_is_open_and_updated_at": { -      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.is_open, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" -    }, -    "by_includes_post_by_and_updated_at": { -      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "by_includes_post_by": {        "map": "// TODO: This view is only used in tests--should we keep it?\nfunction(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit(comment.posted_by, 1);\n      }\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "by_includes_post_by_and_is_open_and_updated_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.is_open, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "by_includes_post_by_and_created_at": {        "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.created_at], 1);\n      }\n    });\n  }\n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "by_includes_post_by_and_updated_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "all": {        "map": "                function(doc) {\n                  if (doc['type'] == 'Ticket') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }    }, -  "couchrest-hash": "9978e2cbeacbe8622c2a7f103bf8130f" +  "couchrest-hash": "b21eaeea8ea66bfda65581b1b7ce06af"  }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/users/User.json b/puppet/modules/site_couchdb/files/designs/users/User.json index 4089ad97..8a82cf4a 100644 --- a/puppet/modules/site_couchdb/files/designs/users/User.json +++ b/puppet/modules/site_couchdb/files/designs/users/User.json @@ -11,12 +11,12 @@      },      "by_created_at_and_one_month_warning_not_sent": {        "map": "function (doc) {\n  if ((doc['type'] == 'User') && (doc['created_at'] != null) && (doc['one_month_warning_sent'] == null)) {\n    emit(doc['created_at'], 1);\n  }    \n}\n", -      "reduce": "function(key, values, rereduce) { return sum(values); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "by_created_at": {        "map": "                function(doc) {\n                  if ((doc['type'] == 'User') && (doc['created_at'] != null)) {\n                    emit(doc['created_at'], 1);\n                  }\n                }\n",        "reduce": "_sum"      }    }, -  "couchrest-hash": "61840ab3ec0f94ef8bbd6dd208db3b70" +  "couchrest-hash": "d854607d299887a347e554176cb79e20"  }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/manifests/master.pp b/puppet/modules/site_couchdb/manifests/master.pp index 5dab6325..c50ed364 100644 --- a/puppet/modules/site_couchdb/manifests/master.pp +++ b/puppet/modules/site_couchdb/manifests/master.pp @@ -7,5 +7,10 @@ class site_couchdb::master {      pwhash_alg          => $site_couchdb::couchdb_pwhash_alg    } +  # couchdb is not available in jessie, and the +  # leap deb repo only hosts a wheeyz version. +  # we install it therefore from unstable +  include site_apt::sid_repo +    include site_check_mk::agent::couchdb::master  } diff --git a/puppet/modules/site_nagios/manifests/server.pp b/puppet/modules/site_nagios/manifests/server.pp index 60a471b7..5c833508 100644 --- a/puppet/modules/site_nagios/manifests/server.pp +++ b/puppet/modules/site_nagios/manifests/server.pp @@ -33,7 +33,7 @@ class site_nagios::server inherits nagios::base {    include site_apache::common    include site_webapp::common_vhost -  include site_apache::module::headers +  include apache::module::headers    File ['nagios_htpasswd'] {      source  => undef, diff --git a/puppet/modules/site_nagios/manifests/server/apache.pp b/puppet/modules/site_nagios/manifests/server/apache.pp index 8dbc7e9b..82962e89 100644 --- a/puppet/modules/site_nagios/manifests/server/apache.pp +++ b/puppet/modules/site_nagios/manifests/server/apache.pp @@ -1,7 +1,25 @@ +# set up apache for nagios  class site_nagios::server::apache { +    include x509::variables +    include site_config::x509::commercial::cert    include site_config::x509::commercial::key    include site_config::x509::commercial::ca +  include apache::module::authn_file +  # "AuthUserFile" +  include apache::module::authz_user +  # "AuthType Basic" +  include apache::module::auth_basic +  # "DirectoryIndex" +  include apache::module::dir +  include apache::module::php5 +  include apache::module::cgi + +  # apache >= 2.4, debian jessie +  if ( $::lsbdistcodename == 'jessie' ) { +    include apache::module::authn_core +  } +  } diff --git a/puppet/modules/site_postfix/templates/checks/helo_access.erb b/puppet/modules/site_postfix/templates/checks/helo_access.erb index bef3c11d..bac2c45a 100644 --- a/puppet/modules/site_postfix/templates/checks/helo_access.erb +++ b/puppet/modules/site_postfix/templates/checks/helo_access.erb @@ -18,4 +18,4 @@  # Reject anybody that HELO's as being in our own domain(s)  # anyone who identifies themselves as us is a virus/spammer -<%= domain %> 554 You are not in domain <%= domain %> +<%= @domain %> 554 You are not in domain <%= @domain %> diff --git a/puppet/modules/site_sshd/manifests/init.pp b/puppet/modules/site_sshd/manifests/init.pp index 170be32c..be0d3368 100644 --- a/puppet/modules/site_sshd/manifests/init.pp +++ b/puppet/modules/site_sshd/manifests/init.pp @@ -1,3 +1,4 @@ +# configures sshd, mosh, authorized keys and known hosts  class site_sshd {    $ssh        = hiera_hash('ssh')    $ssh_config = $ssh['config'] @@ -49,16 +50,32 @@ class site_sshd {      }    } +  # we cannot use the 'hardened' parameter because leap_cli uses an +  # old net-ssh gem that is incompatible with the included +  # "KexAlgorithms curve25519-sha256@libssh.org", +  # see https://leap.se/code/issues/7591 +  # therefore we don't use it here, but include all other options +  # that would be applied by the 'hardened' parameter +  # not all options are available on wheezy +  if ( $::lsbdistcodename == 'wheezy' ) { +    $tail_additional_options = 'Ciphers aes256-ctr +MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160' +  } else { +    $tail_additional_options = 'Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr +MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160' +  } +    ##    ## SSHD SERVER CONFIGURATION    ##    class { '::sshd': -    manage_nagios  => false, -    ports          => [ $ssh['port'] ], -    use_pam        => 'yes', -    hardened_ssl   => 'yes', -    print_motd     => 'no', -    tcp_forwarding => $ssh_config['AllowTcpForwarding'], -    manage_client  => false +    manage_nagios           => false, +    ports                   => [ $ssh['port'] ], +    use_pam                 => 'yes', +    print_motd              => 'no', +    tcp_forwarding          => $ssh_config['AllowTcpForwarding'], +    manage_client           => false, +    use_storedconfigs       => false, +    tail_additional_options => $tail_additional_options    }  } diff --git a/puppet/modules/site_webapp/manifests/apache.pp b/puppet/modules/site_webapp/manifests/apache.pp index ddd04a91..80c7b29b 100644 --- a/puppet/modules/site_webapp/manifests/apache.pp +++ b/puppet/modules/site_webapp/manifests/apache.pp @@ -1,3 +1,4 @@ +# configure apache and passenger to serve the webapp  class site_webapp::apache {    $web_api          = hiera('api') @@ -11,10 +12,10 @@ class site_webapp::apache {    $webapp_domain    = $webapp['domain']    include site_apache::common -  include site_apache::module::headers -  include site_apache::module::alias -  include site_apache::module::expires -  include site_apache::module::removeip +  include apache::module::headers +  include apache::module::alias +  include apache::module::expires +  include apache::module::removeip    include site_webapp::common_vhost    class { 'passenger': use_munin => false } diff --git a/puppet/modules/site_webapp/manifests/hidden_service.pp b/puppet/modules/site_webapp/manifests/hidden_service.pp index 99a756ca..4cf7a8ca 100644 --- a/puppet/modules/site_webapp/manifests/hidden_service.pp +++ b/puppet/modules/site_webapp/manifests/hidden_service.pp @@ -4,10 +4,10 @@ class site_webapp::hidden_service {    $tor_domain       = "${hidden_service['address']}.onion"    include site_apache::common -  include site_apache::module::headers -  include site_apache::module::alias -  include site_apache::module::expires -  include site_apache::module::removeip +  include apache::module::headers +  include apache::module::alias +  include apache::module::expires +  include apache::module::removeip    include tor::daemon    tor::daemon::hidden_service { 'webapp': ports => '80 127.0.0.1:80' } diff --git a/puppet/modules/site_webapp/templates/config.yml.erb b/puppet/modules/site_webapp/templates/config.yml.erb index 19ed6b7b..c2e9f3df 100644 --- a/puppet/modules/site_webapp/templates/config.yml.erb +++ b/puppet/modules/site_webapp/templates/config.yml.erb @@ -1,4 +1,4 @@ -<%- +<%  cert_options = @webapp['client_certificates']  production = {    "admins" => @webapp['admins'], @@ -32,4 +32,4 @@ end  #  # This file is generated by puppet. This file inherits from defaults.yml.  # -<%= scope.function_sorted_yaml({"production" => production}) %> +<%= scope.function_sorted_yaml([{"production" => production}]) %> diff --git a/puppet/modules/sshd b/puppet/modules/sshd -Subproject 750a497758d94c2f5a6cad23cecc3dbde2d2f92 +Subproject 76f4f872f81209a52df2205fd88b5619df58f00 diff --git a/puppet/modules/unbound b/puppet/modules/unbound -Subproject 9997485b8a31abbe0cd1943d09995705c2c8146 +Subproject a26b91dfea3189e6777629fa00d54f51dc41f4d diff --git a/tests/helpers/client_side_db.py b/tests/helpers/client_side_db.py new file mode 100644 index 00000000..2f8c220f --- /dev/null +++ b/tests/helpers/client_side_db.py @@ -0,0 +1,167 @@ +import logging +import os +import tempfile +import getpass +import binascii +import json + +try: +    import requests +    import srp._pysrp as srp +except ImportError: +    pass + +from twisted.internet.defer import inlineCallbacks + +from leap.soledad.client import Soledad + + +""" +Helper functions to give access to client-side Soledad database. +Copied over from soledad/scripts folder. +""" + +# create a logger +logger = logging.getLogger(__name__) + +# DEBUG: enable debug logs +# LOG_FORMAT = '%(asctime)s %(message)s' +# logging.basicConfig(format=LOG_FORMAT, level=logging.DEBUG) + + +safe_unhexlify = lambda x: binascii.unhexlify(x) if ( +    len(x) % 2 == 0) else binascii.unhexlify('0' + x) + + +def _fail(reason): +    logger.error('Fail: ' + reason) +    exit(2) + + +def get_soledad_instance(uuid, passphrase, basedir, server_url, cert_file, +                         token): +    # setup soledad info +    logger.info('UUID is %s' % uuid) +    logger.info('Server URL is %s' % server_url) +    secrets_path = os.path.join( +        basedir, '%s.secret' % uuid) +    local_db_path = os.path.join( +        basedir, '%s.db' % uuid) +    # instantiate soledad +    return Soledad( +        uuid, +        unicode(passphrase), +        secrets_path=secrets_path, +        local_db_path=local_db_path, +        server_url=server_url, +        cert_file=cert_file, +        auth_token=token, +        defer_encryption=True) + + +def _get_api_info(provider): +    info = requests.get( +        'https://'+provider+'/provider.json', verify=False).json() +    return info['api_uri'], info['api_version'] + + +def _login(username, passphrase, provider, api_uri, api_version): +    usr = srp.User(username, passphrase, srp.SHA256, srp.NG_1024) +    auth = None +    try: +        auth = _authenticate(api_uri, api_version, usr).json() +    except requests.exceptions.ConnectionError: +        _fail('Could not connect to server.') +    if 'errors' in auth: +        _fail(str(auth['errors'])) +    return api_uri, api_version, auth + + +def _authenticate(api_uri, api_version, usr): +    api_url = "%s/%s" % (api_uri, api_version) +    session = requests.session() +    uname, A = usr.start_authentication() +    params = {'login': uname, 'A': binascii.hexlify(A)} +    init = session.post( +        api_url + '/sessions', data=params, verify=False).json() +    if 'errors' in init: +        _fail('test user not found') +    M = usr.process_challenge( +        safe_unhexlify(init['salt']), safe_unhexlify(init['B'])) +    return session.put(api_url + '/sessions/' + uname, verify=False, +                       data={'client_auth': binascii.hexlify(M)}) + + +def _get_soledad_info(username, provider, passphrase, basedir): +    api_uri, api_version = _get_api_info(provider) +    auth = _login(username, passphrase, provider, api_uri, api_version) +    # get soledad server url +    service_url = '%s/%s/config/soledad-service.json' % \ +                  (api_uri, api_version) +    soledad_hosts = requests.get(service_url, verify=False).json()['hosts'] +    hostnames = soledad_hosts.keys() +    # allow for choosing the host +    host = hostnames[0] +    if len(hostnames) > 1: +        i = 1 +        print "There are many available hosts:" +        for h in hostnames: +            print "  (%d) %s.%s" % (i, h, provider) +            i += 1 +        choice = raw_input("Choose a host to use (default: 1): ") +        if choice != '': +            host = hostnames[int(choice) - 1] +    server_url = 'https://%s:%d/user-%s' % \ +        (soledad_hosts[host]['hostname'], soledad_hosts[host]['port'], +         auth[2]['id']) +    # get provider ca certificate +    ca_cert = requests.get('https://%s/ca.crt' % provider, verify=False).text +    cert_file = os.path.join(basedir, 'ca.crt') +    with open(cert_file, 'w') as f: +        f.write(ca_cert) +    return auth[2]['id'], server_url, cert_file, auth[2]['token'] + + +def _get_passphrase(args): +    passphrase = args.passphrase +    if passphrase is None: +        passphrase = getpass.getpass( +            'Password for %s@%s: ' % (args.username, args.provider)) +    return passphrase + + +def _get_basedir(args): +    basedir = args.basedir +    if basedir is None: +        basedir = tempfile.mkdtemp() +    elif not os.path.isdir(basedir): +        os.mkdir(basedir) +    logger.info('Using %s as base directory.' % basedir) +    return basedir + + +@inlineCallbacks +def _export_key(args, km, fname, private=False): +    address = args.username + "@" + args.provider +    pkey = yield km.get_key( +        address, OpenPGPKey, private=private, fetch_remote=False) +    with open(args.export_private_key, "w") as f: +        f.write(pkey.key_data) + + +@inlineCallbacks +def _export_incoming_messages(soledad, directory): +    yield soledad.create_index("by-incoming", "bool(incoming)") +    docs = yield soledad.get_from_index("by-incoming", '1') +    i = 1 +    for doc in docs: +        with open(os.path.join(directory, "message_%d.gpg" % i), "w") as f: +            f.write(doc.content["_enc_json"]) +        i += 1 + + +@inlineCallbacks +def _get_all_docs(soledad): +    _, docs = yield soledad.get_all_docs() +    for doc in docs: +        print json.dumps(doc.content, indent=4) diff --git a/tests/helpers/os_helper.rb b/tests/helpers/os_helper.rb index aad67dda..da9ac843 100644 --- a/tests/helpers/os_helper.rb +++ b/tests/helpers/os_helper.rb @@ -9,7 +9,10 @@ class LeapTest      output.each_line.map{|line|        pid = line.split(' ')[0]        process = line.gsub(/(#{pid} |\n)/, '') -      if process =~ /pgrep --full --list-name/ +      # filter out pgrep cmd itself +      # on wheezy hosts, the "process" var contains the whole cmd including all parameters +      # on jessie hosts, it only contains the first cmd (which is the default sheel invoked by 'sh') +      if process =~ /^sh/          nil        else          {:pid => pid, :process => process} diff --git a/tests/helpers/soledad_sync.py b/tests/helpers/soledad_sync.py index 2fb865fc..a1cea069 100755 --- a/tests/helpers/soledad_sync.py +++ b/tests/helpers/soledad_sync.py @@ -1,78 +1,75 @@  #!/usr/bin/env python +""" +soledad_sync.py -# -# Test Soledad sync -# -# This script performs a slightly modified U1DB sync to the Soledad server and -# returns whether that sync was successful or not. -# -# It takes three arguments: -# -#   uuid   -- uuid of the user to sync -#   token  -- a valid session token -#   server -- the url of the soledad server we should connect to -# -# For example: -# -#   soledad_sync.py f6bef0586fcfdb8705e26a58f2d9e580 uYO-4ucEJFksJ6afjmcYwIyap2vW7bv6uLxk0w_RfCc https://199.119.112.9:2323/user-f6bef0586fcfdb8705e26a58f2d9e580 -# +This script exercises soledad synchronization. +Its exit code is 0 if the sync took place correctly, 1 otherwise. +It takes 5 arguments: + +  uuid: uuid of the user to sync +  token: a valid session token +  server: the url of the soledad server we should connect to +  cert_file: the file containing the certificate for the CA that signed the +             cert for the soledad server. +  password: the password for the user to sync + +__author__: kali@leap.se +"""  import os  import sys -import traceback  import tempfile -import shutil -import u1db -from u1db.remote.http_target import HTTPSyncTarget +# This is needed because the twisted shipped with wheezy is too old +# to do proper ssl verification. +os.environ['SKIP_TWISTED_SSL_CHECK'] = '1' -# -# monkey patch U1DB's HTTPSyncTarget to perform token based auth -# +from twisted.internet import defer, reactor -def set_token_credentials(self, uuid, token): -    self._creds = {'token': (uuid, token)} +from client_side_db import get_soledad_instance +from leap.common.events import flags -def _sign_request(self, method, url_query, params): -    uuid, token = self._creds['token'] -    auth = '%s:%s' % (uuid, token) -    return [('Authorization', 'Token %s' % auth.encode('base64')[:-1])] +flags.set_events_enabled(False) -HTTPSyncTarget.set_token_credentials = set_token_credentials -HTTPSyncTarget._sign_request = _sign_request +NUMDOCS = 1 +USAGE = "Usage: %s uuid token server cert_file password" % sys.argv[0] -# -# Create a temporary local u1db replica and attempt to sync to it. -# Returns a failure message if something went wrong. -# -def soledad_sync(uuid, token, server): -    tempdir = tempfile.mkdtemp() -    try: -        db = u1db.open(os.path.join(tempdir, '%s.db' % uuid), True) -        creds = {'token': {'uuid': uuid, 'token': token}} -        db.sync(server, creds=creds, autocreate=False) -    finally: -        shutil.rmtree(tempdir) - -# -# exit codes: -# -# 0 - OK -# 1 - WARNING -# 2 - ERROR -# +def bail(msg, exitcode): +    print "[!] %s" % msg +    sys.exit(exitcode) + + +def create_docs(soledad): +    """ +    Populates the soledad database with dummy messages, so we can exercise +    sending payloads during the sync. +    """ +    deferreds = [] +    for index in xrange(NUMDOCS): +        deferreds.append(soledad.create_doc({'payload': 'dummy'})) +    return defer.gatherResults(deferreds) + +# main program  if __name__ == '__main__': -    try: -        uuid, token, server = sys.argv[1:] -        result = soledad_sync(uuid, token, server) -        if result is None: -            exit(0) -        else: -            print(result) -            exit(1) -    except Exception as exc: -        print(exc.message or str(exc)) -        traceback.print_exc(file=sys.stdout) -        exit(2) + +    tempdir = tempfile.mkdtemp() +    if len(sys.argv) < 6: +        bail(USAGE, 2) +    uuid, token, server, cert_file, passphrase = sys.argv[1:] +    s = get_soledad_instance( +        uuid, passphrase, tempdir, server, cert_file, token) + +    def onSyncDone(sync_result): +        print "SYNC_RESULT:", sync_result +        s.close() +        reactor.stop() + +    def start_sync(): +        d = create_docs(s) +        d.addCallback(lambda _: s.sync()) +        d.addCallback(onSyncDone) + +    reactor.callWhenRunning(start_sync) +    reactor.run() diff --git a/tests/white-box/mx.rb b/tests/white-box/mx.rb index 794a9a41..f49d2ab4 100644 --- a/tests/white-box/mx.rb +++ b/tests/white-box/mx.rb @@ -34,6 +34,9 @@ class Mx < LeapTest    def test_03_Are_MX_daemons_running?      assert_running 'leap_mx'      assert_running '/usr/lib/postfix/master' +    assert_running '/usr/sbin/postfwd' +    assert_running 'postfwd2::cache' +    assert_running 'postfwd2::policy'      assert_running '/usr/sbin/unbound'      pass    end diff --git a/tests/white-box/network.rb b/tests/white-box/network.rb index acb5c5e6..382f857b 100644 --- a/tests/white-box/network.rb +++ b/tests/white-box/network.rb @@ -28,11 +28,18 @@ class Network < LeapTest    def test_02_Is_stunnel_running?      ignore unless $node['stunnel']      good_stunnel_pids = [] +    release = `facter lsbmajdistrelease` +    if release.to_i > 7 +      # on jessie, there is only one stunnel proc running instead of 6 +      expected = 1 +    else +      expected = 6 +    end      $node['stunnel']['clients'].each do |stunnel_type, stunnel_configs|        stunnel_configs.each do |stunnel_name, stunnel_conf|          config_file_name = "/etc/stunnel/#{stunnel_name}.conf"          processes = pgrep(config_file_name) -        assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" +        assert_equal expected, processes.length, "There should be #{expected} stunnel processes running for `#{config_file_name}`"          good_stunnel_pids += processes.map{|ps| ps[:pid]}          assert port = stunnel_conf['accept_port'], 'Field `accept_port` must be present in `stunnel` property.'          assert_tcp_socket('localhost', port) @@ -41,7 +48,7 @@ class Network < LeapTest      $node['stunnel']['servers'].each do |stunnel_name, stunnel_conf|        config_file_name = "/etc/stunnel/#{stunnel_name}.conf"        processes = pgrep(config_file_name) -      assert_equal 6, processes.length, "There should be six stunnel processes running for `#{config_file_name}`" +      assert_equal expected, processes.length, "There should be #{expected} stunnel processes running for `#{config_file_name}`"        good_stunnel_pids += processes.map{|ps| ps[:pid]}        assert accept_port = stunnel_conf['accept_port'], "Field `accept` must be present in property `stunnel.servers.#{stunnel_name}`"        assert_tcp_socket('localhost', accept_port) diff --git a/tests/white-box/webapp.rb b/tests/white-box/webapp.rb index 48507521..e689c143 100644 --- a/tests/white-box/webapp.rb +++ b/tests/white-box/webapp.rb @@ -41,6 +41,35 @@ class Webapp < LeapTest      pass    end +  def test_05_Can_create_and_authenticate_and_delete_user_via_API? +    if property('webapp.allow_registration') +      assert_tmp_user +      pass +    else +      skip "New user registrations are disabled." +    end +  end + +  def test_06_Can_sync_Soledad? +    return unless property('webapp.allow_registration') +    soledad_config = property('definition_files.soledad_service') +    if soledad_config && !soledad_config.empty? +      soledad_server = pick_soledad_server(soledad_config) +      if soledad_server +        assert_tmp_user do |user| +          command = File.expand_path "../../helpers/soledad_sync.py", __FILE__ +          soledad_url = "https://#{soledad_server}/user-#{user.id}" +	  soledad_cert = "/usr/local/share/ca-certificates/leap_ca.crt" +          assert_run "#{command} #{user.id} #{user.session_token} #{soledad_url} #{soledad_cert} #{user.password}" +          assert_user_db_exists(user) +          pass +        end +      end +    else +      skip 'No soledad service configuration' +    end +  end +    private    def url_options  | 
