Commit 325cda9a authored by Adrian Rossouw's avatar Adrian Rossouw

Added key generation code and abstracted the configuration classes a bit more....

Added key generation code and abstracted the configuration classes a bit more. There are now base http classes that handle the synching to remote servers.
parent 6ef19c36
......@@ -19,6 +19,12 @@ class provisionService_http_apache extends provisionService_http_public {
$this->configs['site'][] = 'provisionConfig_apache_site';
}
/**
* Guess at the likely value of the http_restart_cmd.
*
* This method is a static so that it can be re-used by the apache_ssl
* service, even though it does not inherit this class.
*/
public static function apache_restart_cmd() {
$command = '/usr/sbin/apachectl'; // A proper default for most of the world
foreach (explode(':', $_SERVER['PATH']) as $path) {
......@@ -49,42 +55,12 @@ class provisionService_http_apache extends provisionService_http_public {
}
}
class provisionConfig_apache extends provisionConfig {
function write() {
parent::write();
$this->data['server']->sync($this->filename());
}
function unlink() {
parent::unlink();
$this->data['server']->sync($this->filename());
}
}
/**
* Apache server level configuration file class
*/
class provisionConfig_apache_server extends provisionConfig_apache {
public $template = 'server.tpl.php';
public $description = 'apache server configuration file';
function write() {
parent::write();
// We link the apache.config file on the remote server to the right version.
$cmd = sprintf('ln -sf %s %s',
escapeshellarg($this->data['server']->config_path . '/apache.conf'),
escapeshellarg($this->data['server']->aegir_root . '/config/apache.conf')
);
$this->data['server']->shell_exec($cmd);
}
function filename() {
return $this->data['server']->config_path . '/apache.conf';
}
class provisionConfig_apache_server extends provisionConfig_http_server {
function process() {
parent::process();
$this->data['extra_config'] = "# Extra configuration from modules:\n";
$this->data['extra_config'] .= join("\n", drush_command_invoke_all('provision_apache_server_config', $this->data));
}
......@@ -93,15 +69,9 @@ class provisionConfig_apache_server extends provisionConfig_apache {
/**
* Apache platform level configuration file class
*/
class provisionConfig_apache_platform extends provisionConfig_apache {
public $template = 'platform.tpl.php';
public $description = 'apache platform configuration file';
function filename() {
return $this->data['http_platformd_path'] . '/' . ltrim($this->owner->name, '@') . '.conf';
}
class provisionConfig_apache_platform extends provisionConfig_http_platform {
function process() {
parent::process();
$this->data['extra_config'] = "# Extra configuration from modules:\n";
$this->data['extra_config'] .= join("\n", drush_command_invoke_all('provision_apache_dir_config', $this->data));
}
......@@ -110,23 +80,9 @@ class provisionConfig_apache_platform extends provisionConfig_apache {
/**
* Apache site level config class. Virtual host.
*/
class provisionConfig_apache_site extends provisionConfig_apache {
public $template = 'vhost.tpl.php';
public $description = 'apache site configuration file';
function filename() {
return $this->data['http_vhostd_path'] . '/' . $this->uri;
}
class provisionConfig_apache_site extends provisionConfig_http_site {
function process() {
if ($this->aliases && !is_array($this->aliases)) {
$this->aliases = explode(",", $this->aliases);
}
if (!$this->site_enabled) {
$this->template = 'vhost_disabled.tpl.php';
}
parent::process();
$this->data['extra_config'] = "# Extra configuration from modules:\n";
$this->data['extra_config'] .= join("\n", drush_command_invoke_all('provision_apache_vhost_config', $this->uri, $this->data));
}
......
......@@ -7,29 +7,88 @@
* The Apache +SSL service implementation.
*/
// Include the apache service implementation.
// Even though we don't extend it, we do make use of it's config classes.
include_once(dirname(__FILE__) . '../apache/apache_service.inc');
/**
* Apache SSL service class.
*
* This class doesn't extend the apache service itself, so there may
* be some duplication of code between them. The majority of the
* functionality is however implemented in the provisionService_http_public
* class, which we do extend.
*/
class provisionService_http_apache_ssl extends provisionService_http_ssl {
// We share the application name with apache.
protected $application_name = 'apache';
protected $has_restart_cmd = TRUE;
function default_restart_cmd() {
// The apache service defines it's restart command as a static
// method so that we can make use of it here.
return provisionService_http_apache::apache_restart_cmd();
}
class provisionService_http_apache_ssl extends provisionService_http_apache {
public $ssl_enabled = TRUE;
/**
* Initialize the configuration files.
*
* These config classes are a mix of the SSL and Non-SSL apache
* classes. In some cases they extend the Apache classes too.
*/
function init() {
parent::init();
$this->configs['server'] = array();
// Replace the server config with our own. See the class for more info.
$this->configs['server'][] = 'provisionConfig_apache_server_ssl';
// Just re-use the standard platform config.
$this->configs['platform'][] = 'provisionConfig_apache_platform';
// We generate both an SSL and a non-SSL config file.
$this->configs['site'][] = 'provisionConfig_apache_site';
$this->configs['site'][] = 'provisionConfig_apache_site_ssl';
}
/**
* Restart apache to pick up the new config files.
*/
function parse_configs() {
return $this->restart();
}
}
class provisionConfig_apache_server_ssl extends provisionConfig_apache_server {
/**
* Server config file for Apache + SSL.
*
* This configuration file replaces the Apache server configuration file, but
* inside the template, the original file is once again included.
*
* This config is primarily reponsible for enabling the SSL relation settings,
* so that individual sites can just enable them.
*/
class provisionConfig_apache_server_ssl extends provisionConfig_http_server {
public $template = 'server_ssl.tpl.php';
}
// We use the same extra_config as the apache_server config class.
function process() {
parent::process();
$this->data['extra_config'] = "# Extra configuration from modules:\n";
$this->data['extra_config'] .= join("\n", drush_command_invoke_all('provision_apache_server_config', $this->data));
}
}
class provisionConfig_apache_site_ssl extends provisionConfig_apache_site {
public $template = 'vhost_ssl.tpl.php';
/**
* Virtual host config file for Apache + SSL.
*
* This file is created in addition to the existing virtual host,
* and includes some extra directives.
*/
class provisionConfig_apache_ssl_site extends provisionConfig_http_ssl_site {
public $description = 'apache ssl configuration file';
function filename() {
$this->data['http_vhostd_path'] . '/' . $this->uri . '_ssl';
}
}
<?php foreach ($ip_addresses as $ip) : ?>
NameVirtualHost <?php print $ip . ":" . $http_ssl_port . "\n"; ?>
<?php endforeach; ?>
<IfModule !ssl_module>
LoadModule ssl_module modules/mod_ssl.so
</IfModule>
......
<VirtualHost <?php print "{$ip_address}:{$http_ssl_port}"; ?>>
<?php if ($this->site_mail) : ?>
ServerAdmin <?php print $this->site_mail; ?>
<?php endif;?>
DocumentRoot <?php print $this->root; ?>
ServerName <?php print $this->uri; ?>
SetEnv db_type <?php print urlencode($db_type); ?>
SetEnv db_name <?php print urlencode($db_name); ?>
SetEnv db_user <?php print urlencode($db_user); ?>
SetEnv db_passwd <?php print urlencode($db_passwd); ?>
SetEnv db_host <?php print urlencode($db_host); ?>
SetEnv db_port <?php print urlencode($db_port); ?>
<?php if (!$this->redirection && is_array($this->aliases)) :
foreach ($this->aliases as $alias_url) :
if (trim($alias_url)) : ?>
ServerAlias <?php print $alias_url; ?>
<?php
endif;
endforeach;
endif; ?>
<?php print $extra_config; ?>
# Error handler for Drupal > 4.6.7
<Directory "<?php print $this->site_path; ?>/files">
SetHandler This_is_a_Drupal_security_line_do_not_remove
</Directory>
</VirtualHost>
<?php
// $Id$
/**
* @file
* Configuration classes for the HTTP service.
*/
/**
* Base class for HTTP config files.
*
* This class will publish the config files to remote
* servers automatically.
*/
class provisionConfig_http extends provisionConfig {
function write() {
parent::write();
$this->data['server']->sync($this->filename());
}
function unlink() {
parent::unlink();
$this->data['server']->sync($this->filename());
}
}
/**
* Base configuration class for server level http configs.
*
* This class uses the service defined application_name, to generate
* a top level $app_name.conf for the service.
*
* Each server has it's own configuration, and this class will
* automatically generate a symlink to the correct file for each
* server.
*/
class provisionConfig_http_server extends provisionConfig_http {
public $template = 'server.tpl.php';
public $description = 'web server configuration file';
function write() {
parent::write();
if (isset($this->data['application_name'])) {
$file = $this->data['application_name'] . '.conf';
// We link the app_name.conf file on the remote server to the right version.
$cmd = sprintf('ln -sf %s %s',
escapeshellarg($this->data['server']->config_path . '/' . $file),
escapeshellarg($this->data['server']->aegir_root . '/config/' . $file)
);
$this->data['server']->shell_exec($cmd);
}
}
function filename() {
if (isset($this->data['application_name'])) {
$file = $this->data['application_name'] . '.conf';
return $this->data['server']->config_path . '/' . $file;
}
else {
return FALSE;
}
}
}
/**
* Base class for platform configuration files.
*/
class provisionConfig_http_platform extends provisionConfig_http {
public $template = 'platform.tpl.php';
public $description = 'platform configuration file';
function filename() {
return $this->data['http_platformd_path'] . '/' . ltrim($this->owner->name, '@') . '.conf';
}
}
/**
* Base class for virtual host configuration files.
*/
class provisionConfig_http_site extends provisionConfig_http {
public $template = 'vhost.tpl.php';
public $description = 'virtual host configuration file';
function filename() {
return $this->data['http_vhostd_path'] . '/' . $this->uri;
}
function process() {
parent::process();
if ($this->aliases && !is_array($this->aliases)) {
$this->aliases = explode(",", $this->aliases);
}
if (!$this->site_enabled) {
$this->template = 'vhost_disabled.tpl.php';
}
}
}
......@@ -2,7 +2,6 @@
include_once(dirname(__FILE__) . '/../provision.service.inc');
function http_provision_services() {
return array('http' => NULL);
}
......@@ -14,6 +13,7 @@ class provisionService_http extends provisionService {
protected $ssl_enabled = FALSE;
}
// Public http service , as in non-encrypted and listening on a port.
class provisionService_http_public extends provisionService_http {
protected $has_port = TRUE;
......@@ -118,5 +118,8 @@ class provisionService_http_public extends provisionService_http {
$this->context->platform->server,
);
}
}
include_once('http.config.inc');
include_once('http.ssl.inc');
<?php
// $Id$
/**
* @file The base implementation of the SSL capabale web service.
*/
/**
* The base class for SSL supporting servers.
*
* In general, these function the same as normal servers, but have an extra
* port and some extra variables in their templates.
*/
class provisionService_http_ssl extends provisionService_http_public {
protected $ssl_enabled = TRUE;
function default_ssl_port() {
return 443;
}
function init() {
parent::init();
// SSL Port.
$this->server->setProperty('http_ssl_port', $this->default_ssl_port());
// SSL certificate store.
// The certificates are generated from here, and distributed to the servers,
// as needed.
$this->server->ssld_path = "{$this->server->aegir_root}/config/ssl.d";
// SSL certificate store for this server.
// This server's certificates will be stored here.
$this->server->http_ssld_path = "{$this->server->config_path}/ssl.d";
}
function config_data($config = null, $class = null) {
$data = parent::config_data($config, $class);
if ($config == 'site' && $this->context->ssl_enabled) {
if ($ssl_key = $this->context->ssl_key) {
// Retrieve the paths to the cert and key files.
// they are generated if not found.
$certs = $this->get_certificates($ssl_key);
$data = array_merge($data, $certs);
// assign ip address based on ssl_key
$data['ip_address'] = $this->server->ip_addresses[0];
}
}
return $data;
}
/**
* Retrieve an array containing the actual files for this ssl_key.
*
* If the files could not be found, this function will proceed to generate
* certificates for the current site, so that the operation can complete
* succesfully.
*/
function get_certificates($ssl_key) {
$source_path = "{$this->server->ssld_path}/{$ssl_key}";
$certs['ssl_cert_key_source'] = "{$source_path}/openssl.key";
$certs['ssl_cert_source'] = "{$source_path}/openssl.crt";
foreach ($certs as $cert) {
$exists = provision_file()->exists($cert).status();
if (!$exists) {
// if any of the files don't exist, regenerate them.
$this->generate_certificates($ssl_key);
// break out of the loop.
break;
}
}
$path = "{$this->server->http_ssld_path}/{$ssl_key}";
$certs['ssl_cert_key'] = "{$path}/openssl.key";
$certs['ssl_cert'] = "{$path}/openssl.crt";
return $certs;
}
function generate_certificates($ssl_key) {
$path = "{$this->server->ssld_path}/{$ssl_key}";
$created = provision_file()->create_dir($path,
dt("SSL certificate directory for %ssl_key", array(
'%ssl_key' => $ssl_key
)), 0700)->status();
if ($created) {
$pass = 'pass';
// generate a key
drush_shell_exec('openssl genrsa -passout pass:%s -des3 -out %s/openssl.key.orig 1024', $pass, $path);
// unsign it
drush_shell_exec('openssl rsa -passin pass:%s -in %s/openssl.key.orig -out %s/openssl.key', $pass, $path, $path);
// Generate the CSR
$ident = "/C=us/CN={$this->context->uri}/OU={$this->context->uri}/emailAddress=admin@{$this->context->uri}";
drush_shell_exec("openssl req -new -subj '%s' -key %s/openssl.key -out %s/openssl.csr -batch", $ident, $path, $path);
drush_shell_exec("openssl x509 -req -days 365 -in %s/openssl.csr -signkey %s/openssl.key -out %s/openssl.crt", $path, $path, $path);
}
}
function verify() {
if ($this->context->type === 'server') {
provision_file()->create_dir($this->server->ssld_path, dt("Central SSL certificate repository."), 0700);
provision_file()->create_dir($this->server->http_ssld_path,
dt("SSL certificate repository for %server",
array('%server' => $this->server->remote_host)), 0700);
$this->sync($this->server->http_ssld_path, array(
'exclude' => $this->server->http_ssld_path . '/*', // Make sure remote directory is created
));
}
// Call the parent at the end. it will restart the server when it finishes.
parent::verify();
}
}
class provisionConfig_http_ssl_site extends provisionConfig_http_site {
public $template = 'vhost_ssl.tpl.php';
function __construct($owner, $data = array()) {
parent::__construct($owner, $data);
if (!$this->ssl_enabled || !$this->ssl_key) {
//throw new provisionException_continue("SSL has not been enabled for this site. SSL vhost not necessary");
}
}
function filename() {
$this->data['http_vhostd_path'] . '/' . $this->uri . '_ssl';
}
}
......@@ -280,6 +280,5 @@ class provisionConfig_drushrc_site extends provisionConfig_drushrc {
function filename() {
return $this->site_path . '/drushrc.php';
}
}
......@@ -355,6 +355,24 @@ class provisionChainedState {
}
}
// Base class for provision exceptions.
class provisionException extends Exception {
}
/**
* Signal for parent to continue processing.
*
* The primary use for this class is for the config
* classes to be able to signal to it's caller, that
* the configuration file was not needed, and to
* continue on.
*/
class provisionException_continue extends provisionException {
}
include_once('provision.environment.inc');
include_once('provision.service.inc');
include_once('provision.file.inc');
......
......@@ -48,14 +48,20 @@ class provisionService extends provisionChainedState {
if (isset($this->configs[$config])) {
// We cast to array here to silently accept the non array version
foreach ((array) $this->configs[$config] as $class) {
$config = new $class($this->context, $this->config_data($config));
$config->write();
try {
$config = new $class($this->context, $this->config_data($config));
$config->write();
}
catch (provisionException_continue $e) {
// The service or configuration class has signaled that the config file
// was uneccesary, and we should continue normally.
}
}
}
}
/**
* Delete a configurationf file.
* Delete a configuration file.
*
* This method will fetch the class to instantiate from the internal
* $this->configs control array.
......@@ -64,8 +70,14 @@ class provisionService extends provisionChainedState {
if (isset($this->configs[$config])) {
// We cast to array here to silently accept the non array version
foreach ((array) $this->configs[$config] as $class) {
$config = new $class($this->context, $this->config_data($config, $class));
$config->unlink();
try {
$config = new $class($this->context, $this->config_data($config, $class));
$config->unlink();
}
catch (provisionException_continue $e) {
// The service or configuration class has signaled that the config file
// was uneccesary, and we should continue normally.
}
}
}
}
......@@ -75,8 +87,13 @@ class provisionService extends provisionChainedState {
*/
function config_data($config = null, $class = null) {
$data = array();
// Always pass the server this service is running on to configs.
$data['server'] = $this->server;
if (!is_null($this->application_name)) {
// This value may be useful to standardize paths in config files.
$data['application_name'] = $this->application_name;
}
return $data;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment