Ejemplo n.º 1
0
    def _choose_vhost_from_list(self, target_name):
        # Select a vhost from a list
        vhost = display_ops.select_vhost(target_name, self.vhosts)
        if vhost is None:
            logger.error(
                "No vhost exists with servername or alias of: %s. "
                "No vhost was selected. Please specify servernames "
                "in the Apache config", target_name)
            raise errors.PluginError("No vhost selected")

        elif not vhost.ssl:
            addrs = self._get_proposed_addrs(vhost, "443")
            # TODO: Conflicts is too conservative
            if not any(vhost.enabled and vhost.conflicts(addrs) for vhost in self.vhosts):
                vhost = self.make_vhost_ssl(vhost)
            else:
                logger.error(
                    "The selected vhost would conflict with other HTTPS "
                    "VirtualHosts within Apache. Please select another "
                    "vhost or add ServerNames to your configuration.")
                raise errors.PluginError(
                    "VirtualHost not able to be selected.")

        self.assoc[target_name] = vhost
        return vhost
Ejemplo n.º 2
0
    def prepare(self):  # pylint: disable=missing-docstring
        path_map = self.conf("map")

        if not path_map:
            raise errors.PluginError("--{0} must be set".format(
                self.option_name("path")))
        for name, path in path_map.items():
            if not os.path.isdir(path):
                raise errors.PluginError(path + " does not exist or is not a directory")
            self.full_roots[name] = os.path.join(path, challenges.HTTP01.URI_ROOT_PATH)

            logger.debug("Creating root challenges validation dir at %s",
                         self.full_roots[name])
            try:
                os.makedirs(self.full_roots[name])
                # Set permissions as parent directory (GH #1389)
                # We don't use the parameters in makedirs because it
                # may not always work
                # https://stackoverflow.com/questions/5231901/permission-problems-when-creating-a-dir-with-os-makedirs-python
                stat_path = os.stat(path)
                filemode = stat.S_IMODE(stat_path.st_mode)
                os.chmod(self.full_roots[name], filemode)
                # Set owner and group, too
                os.chown(self.full_roots[name], stat_path.st_uid,
                          stat_path.st_gid)

            except OSError as exception:
                if exception.errno != errno.EEXIST:
                    raise errors.PluginError(
                        "Couldn't create root for {0} http-01 "
                        "challenge responses: {1}", name, exception)
Ejemplo n.º 3
0
    def update_runtime_variables(self, ctl):
        """"

        .. note:: Compile time variables (apache2ctl -V) are not used within the
            dynamic configuration files.  These should not be parsed or
            interpreted.

        .. todo:: Create separate compile time variables... simply for arg_get()

        """
        stdout = self._get_runtime_cfg(ctl)

        variables = dict()
        matches = re.compile(r"Define: ([^ \n]*)").findall(stdout)
        try:
            matches.remove("DUMP_RUN_CFG")
        except ValueError:
            raise errors.PluginError("Unable to parse runtime variables")

        for match in matches:
            if match.count("=") > 1:
                logger.error("Unexpected number of equal signs in "
                             "apache2ctl -D DUMP_RUN_CFG")
                raise errors.PluginError(
                    "Error parsing Apache runtime variables")
            parts = match.partition("=")
            variables[parts[0]] = parts[2]

        self.variables = variables
Ejemplo n.º 4
0
    def get_version(self):
        """Return version of Apache Server.

        Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))

        :returns: version
        :rtype: tuple

        :raises .PluginError: if unable to find Apache version

        """
        try:
            proc = subprocess.Popen([self.conf("ctl"), "-v"],
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            text = proc.communicate()[0]
        except (OSError, ValueError):
            raise errors.PluginError("Unable to run %s -v" % self.conf("ctl"))

        regex = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
        matches = regex.findall(text)

        if len(matches) != 1:
            raise errors.PluginError("Unable to find Apache version")

        return tuple([int(i) for i in matches[0].split(".")])
Ejemplo n.º 5
0
    def prepare(self):
        """Prepare the plugin

        Get apikey and store in config
        """

        self.api_key = self._api_key_from_args() or\
            self._api_key_from_env() or\
            self._api_key_from_gandi_cli()

        if not self.api_key:
            raise errors.PluginError("Api key is missing, couldn't found from "
                                     "neither gandi.cli, environment"
                                     "(GANDI_API_KEY), nor --{0}".format(
                                         self.option_name('api-key')))

        self.shs_name = self.conf('name')
        if not self.shs_name:
            raise errors.PluginError("--{0} is a required parameter,"
                                     "please provide a valid simple hosting "
                                     "name".format(self.option_name('name')))

        self.vhost = self.conf('vhost')

        if not re.match('^(php|ruby|python)', self.shs_info['type']):
            raise errors.PluginError(
                "Sorry, only php and ruby instances are supported for now, "
                "we're doing our best to get everything supported with "
                "Let's Encrypt. Please check {0} for newer versions.".format(
                    UPSTREAM_URL))
Ejemplo n.º 6
0
    def _verify_no_redirects(self, vhost):
        """Checks to see if existing redirect is in place.

        Checks to see if virtualhost already contains a rewrite or redirect
        returns boolean, integer

        :param vhost: vhost to check
        :type vhost: :class:`~letsencrypt_apache.obj.VirtualHost`

        :raises errors.PluginError: When another redirection exists

        """
        rewrite_path = self.parser.find_dir(
            "RewriteRule", None, start=vhost.path)
        redirect_path = self.parser.find_dir("Redirect", None, start=vhost.path)

        if redirect_path:
            # "Existing Redirect directive for virtualhost"
            raise errors.PluginError("Existing Redirect present on HTTP vhost.")
        if rewrite_path:
            # "No existing redirection for virtualhost"
            if len(rewrite_path) != len(constants.REWRITE_HTTPS_ARGS):
                raise errors.PluginError("Unknown Existing RewriteRule")
            for match, arg in itertools.izip(
                    rewrite_path, constants.REWRITE_HTTPS_ARGS):
                if self.aug.get(match) != arg:
                    raise errors.PluginError("Unknown Existing RewriteRule")
            raise errors.PluginError(
                "Let's Encrypt has already enabled redirection")
Ejemplo n.º 7
0
 def _get_root_path(self, achall):
     try:
         path = self.full_roots[achall.domain]
     except KeyError:
         raise errors.PluginError("Missing --webroot-path for domain: {0}"
                                  .format(achall.domain))
     if not os.path.exists(path):
         raise errors.PluginError("Mysteriously missing path {0} for domain: {1}"
                                  .format(path, achall.domain))
     return path
Ejemplo n.º 8
0
 def _path_for_achall(self, achall):
     try:
         path = self.full_roots[achall.domain]
     except KeyError:
         raise errors.PluginError("Missing --webroot-path for domain: {0}"
                                  .format(achall.domain))
     if not os.path.exists(path):
         raise errors.PluginError("Mysteriously missing path {0} for domain: {1}"
                                  .format(path, achall.domain))
     return os.path.join(path, achall.chall.encode("token"))
Ejemplo n.º 9
0
    def prepare(self):  # pylint: disable=missing-docstring
        path_map = self.conf("map")

        if not path_map:
            raise errors.PluginError(
                "Missing parts of webroot configuration; please set either "
                "--webroot-path and --domains, or --webroot-map. Run with "
                " --help webroot for examples.")
        for name, path in path_map.items():
            if not os.path.isdir(path):
                raise errors.PluginError(
                    path + " does not exist or is not a directory")
            self.full_roots[name] = os.path.join(
                path, challenges.HTTP01.URI_ROOT_PATH)

            logger.debug("Creating root challenges validation dir at %s",
                         self.full_roots[name])

            # Change the permissions to be writable (GH #1389)
            # Umask is used instead of chmod to ensure the client can also
            # run as non-root (GH #1795)
            old_umask = os.umask(0o022)

            try:
                # This is coupled with the "umask" call above because
                # os.makedirs's "mode" parameter may not always work:
                # https://stackoverflow.com/questions/5231901/permission-problems-when-creating-a-dir-with-os-makedirs-python
                os.makedirs(self.full_roots[name], 0o0755)

                # Set owner as parent directory if possible
                try:
                    stat_path = os.stat(path)
                    os.chown(self.full_roots[name], stat_path.st_uid,
                             stat_path.st_gid)
                except OSError as exception:
                    if exception.errno == errno.EACCES:
                        logger.debug(
                            "Insufficient permissions to change owner and uid - ignoring"
                        )
                    else:
                        raise errors.PluginError(
                            "Couldn't create root for {0} http-01 "
                            "challenge responses: {1}", name, exception)

            except OSError as exception:
                if exception.errno != errno.EEXIST:
                    raise errors.PluginError(
                        "Couldn't create root for {0} http-01 "
                        "challenge responses: {1}", name, exception)
            finally:
                os.umask(old_umask)
Ejemplo n.º 10
0
    def get_version(self):
        """Return version of Nginx Server.

        Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))

        :returns: version
        :rtype: tuple

        :raises .PluginError:
            Unable to find Nginx version or version is unsupported

        """
        try:
            proc = subprocess.Popen(
                [self.conf('ctl'), "-c", self.nginx_conf, "-V"],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            text = proc.communicate()[1]  # nginx prints output to stderr
        except (OSError, ValueError) as error:
            logging.debug(error, exc_info=True)
            raise errors.PluginError(
                "Unable to run %s -V" % self.conf('ctl'))

        version_regex = re.compile(r"nginx/([0-9\.]*)", re.IGNORECASE)
        version_matches = version_regex.findall(text)

        sni_regex = re.compile(r"TLS SNI support enabled", re.IGNORECASE)
        sni_matches = sni_regex.findall(text)

        ssl_regex = re.compile(r" --with-http_ssl_module")
        ssl_matches = ssl_regex.findall(text)

        if not version_matches:
            raise errors.PluginError("Unable to find Nginx version")
        if not ssl_matches:
            raise errors.PluginError(
                "Nginx build is missing SSL module (--with-http_ssl_module).")
        if not sni_matches:
            raise errors.PluginError("Nginx build doesn't support SNI")

        nginx_version = tuple([int(i) for i in version_matches[0].split(".")])

        # nginx < 0.8.48 uses machine hostname as default server_name instead of
        # the empty string
        if nginx_version < (0, 8, 48):
            raise errors.NotSupportedError("Nginx version must be 0.8.48+")

        return nginx_version
Ejemplo n.º 11
0
 def install_cert(self):
     """Install certificate to the domain repository in Plesk."""
     request = {
         'packet': {
             'certificate': {
                 'install': [{
                     'name': self.cert_name()
                 }, {
                     'site': self.domain
                 }, {
                     'content': [
                         {
                             'csr': {}
                         },
                         {
                             'pvt': self.key_data
                         },
                         {
                             'cert': self.cert_data
                         },
                         {
                             'ca': self.chain_data
                         },
                     ]
                 }]
             }
         }
     }
     response = self.plesk_api_client.request(request)
     api_result = response['packet']['certificate']['install']['result']
     if 'ok' != api_result['status']:
         error_text = str(api_result['errtext'])
         raise errors.PluginError('Install certificate failure: %s' %
                                  error_text)
     self.cert_installed = True
Ejemplo n.º 12
0
    def _perform_single(self, achall):
        # same path for each challenge response would be easier for
        # users, but will not work if multiple domains point at the
        # same server: default command doesn't support virtual hosts
        response, validation = achall.response_and_validation()

        port = (response.port if self.config.http01_port is None else int(
            self.config.http01_port))
        command = self.CMD_TEMPLATE.format(
            root=self._root,
            achall=achall,
            response=response,
            # TODO(kuba): pipes still necessary?
            validation=pipes.quote(validation),
            encoded_token=achall.chall.encode("token"),
            port=port)
        if self.conf("test-mode"):
            logger.debug("Test mode. Executing the manual command: %s",
                         command)
            # sh shipped with OS X does't support echo -n, but supports printf
            try:
                self._httpd = subprocess.Popen(
                    command,
                    # don't care about setting stdout and stderr,
                    # we're in test mode anyway
                    shell=True,
                    executable=None,
                    # "preexec_fn" is UNIX specific, but so is "command"
                    preexec_fn=os.setsid)
            except OSError as error:  # ValueError should not happen!
                logger.debug("Couldn't execute manual command: %s",
                             error,
                             exc_info=True)
                return False
            logger.debug("Manual command running as PID %s.", self._httpd.pid)
            # give it some time to bootstrap, before we try to verify
            # (cert generation in case of simpleHttpS might take time)
            self._test_mode_busy_wait(port)
            if self._httpd.poll() is not None:
                raise errors.Error("Couldn't execute manual command")
        else:
            if not self.conf("public-ip-logging-ok"):
                if not zope.component.getUtility(interfaces.IDisplay).yesno(
                        self.IP_DISCLAIMER, "Yes", "No"):
                    raise errors.PluginError(
                        "Must agree to IP logging to proceed")

            self._notify_and_wait(
                self.MESSAGE_TEMPLATE.format(validation=validation,
                                             response=response,
                                             uri=achall.chall.uri(
                                                 achall.domain),
                                             command=command))

        if not response.simple_verify(achall.chall, achall.domain,
                                      achall.account_key.public_key(),
                                      self.config.http01_port):
            logger.warning("Self-verify of challenge failed.")

        return response
Ejemplo n.º 13
0
    def get_arg(self, match):
        """Uses augeas.get to get argument value and interprets result.

        This also converts all variables and parameters appropriately.

        """
        value = self.aug.get(match)

        # No need to strip quotes for variables, as apache2ctl already does
        # this, but we do need to strip quotes for all normal arguments.

        # Note: normal argument may be a quoted variable
        # e.g. strip now, not later
        value = value.strip("'\"")

        variables = ApacheParser.arg_var_interpreter.findall(value)

        for var in variables:
            # Strip off ${ and }
            try:
                value = value.replace(var, self.variables[var[2:-1]])
            except KeyError:
                raise errors.PluginError("Error Parsing variable: %s" % var)

        return value
Ejemplo n.º 14
0
    def _enable_redirect(self, ssl_vhost, unused_options):
        """Redirect all equivalent HTTP traffic to ssl_vhost.

        .. todo:: This enhancement should be rewritten and will
           unfortunately require lots of debugging by hand.

        Adds Redirect directive to the port 80 equivalent of ssl_vhost
        First the function attempts to find the vhost with equivalent
        ip addresses that serves on non-ssl ports
        The function then adds the directive

        .. note:: This function saves the configuration

        :param ssl_vhost: Destination of traffic, an ssl enabled vhost
        :type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`

        :param unused_options: Not currently used
        :type unused_options: Not Available

        :returns: Success, general_vhost (HTTP vhost)
        :rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)

        :raises .errors.PluginError: If no viable HTTP host can be created or
            used for the redirect.

        """
        if "rewrite_module" not in self.parser.modules:
            self.enable_mod("rewrite")
        general_vh = self._get_http_vhost(ssl_vhost)

        if general_vh is None:
            # Add virtual_server with redirect
            logger.debug("Did not find http version of ssl virtual host "
                         "attempting to create")
            redirect_addrs = self._get_proposed_addrs(ssl_vhost)
            for vhost in self.vhosts:
                if vhost.enabled and vhost.conflicts(redirect_addrs):
                    raise errors.PluginError(
                        "Unable to find corresponding HTTP vhost; "
                        "Unable to create one as intended addresses conflict; "
                        "Current configuration does not support automated "
                        "redirection")
            self._create_redirect_vhost(ssl_vhost)
        else:
            # Check if redirection already exists
            self._verify_no_redirects(general_vh)

            # Add directives to server
            # Note: These are not immediately searchable in sites-enabled
            #     even with save() and load()
            self.parser.add_dir(general_vh.path, "RewriteEngine", "on")
            self.parser.add_dir(general_vh.path, "RewriteRule",
                                constants.REWRITE_HTTPS_ARGS)
            self.save_notes += ("Redirecting host in %s to ssl vhost in %s\n" %
                                (general_vh.filep, ssl_vhost.filep))
            self.save()

            logger.info("Redirecting vhost in %s to ssl vhost in %s",
                        general_vh.filep, ssl_vhost.filep)
Ejemplo n.º 15
0
    def _perform_single(self, achall):
        # same path for each challenge response would be easier for
        # users, but will not work if multiple domains point at the
        # same server: default command doesn't support virtual hosts
        response, validation = achall.gen_response_and_validation(
            tls=False)  # SimpleHTTP TLS is dead: ietf-wg-acme/acme#7

        port = (response.port if self.config.simple_http_port is None
                else int(self.config.simple_http_port))
        command = self.CMD_TEMPLATE.format(
            root=self._root, achall=achall, response=response,
            validation=pipes.quote(validation.json_dumps()),
            encoded_token=achall.chall.encode("token"),
            ct=response.CONTENT_TYPE, port=port)
        if self.conf("test-mode"):
            logger.debug("Test mode. Executing the manual command: %s", command)
            # sh shipped with OS X does't support echo -n
            executable = "/bin/bash" if sys.platform == "darwin" else None
            try:
                self._httpd = subprocess.Popen(
                    command,
                    # don't care about setting stdout and stderr,
                    # we're in test mode anyway
                    shell=True,
                    executable=executable,
                    # "preexec_fn" is UNIX specific, but so is "command"
                    preexec_fn=os.setsid)
            except OSError as error:  # ValueError should not happen!
                logger.debug(
                    "Couldn't execute manual command: %s", error, exc_info=True)
                return False
            logger.debug("Manual command running as PID %s.", self._httpd.pid)
            # give it some time to bootstrap, before we try to verify
            # (cert generation in case of simpleHttpS might take time)
            self._test_mode_busy_wait(port)
            if self._httpd.poll() is not None:
                raise errors.Error("Couldn't execute manual command")
        else:
            if not zope.component.getUtility(interfaces.IDisplay).yesno(
                    self.IP_DISCLAIMER, "Yes", "No"):
                raise errors.PluginError("Must agree to IP logging to proceed")

            self._notify_and_wait(self.MESSAGE_TEMPLATE.format(
                validation=validation.json_dumps(), response=response,
                uri=response.uri(achall.domain, achall.challb.chall),
                ct=response.CONTENT_TYPE, command=command))

        if response.simple_verify(
                achall.chall, achall.domain,
                achall.account_key.public_key(), self.config.simple_http_port):
            return response
        else:
            logger.error(
                "Self-verify of challenge failed, authorization abandoned.")
            if self.conf("test-mode") and self._httpd.poll() is not None:
                # simply verify cause command failure...
                return False
            return None
Ejemplo n.º 16
0
    def shs_info(self):
        if not hasattr(self, 'api_key'):
            raise errors.PluginError("Api key is missing")
        if not hasattr(self, 'shs_name'):
            raise errors.PluginError("Simple hosting name is missing")

        if self._shs_info:
            return self._shs_info

        api = self._api()

        list = api.paas.list(self.api_key, {'name': self.shs_name})
        if not list:
            raise errors.PluginError("Couldn't find any match for {0}".format(
                self.shs_name))

        self._shs_info = api.paas.info(self.api_key, list[0]['id'])
        return self._shs_info
Ejemplo n.º 17
0
    def _enable_redirect(self, ssl_vhost, unused_options):
        """Redirect all equivalent HTTP traffic to ssl_vhost.

        .. todo:: This enhancement should be rewritten and will
           unfortunately require lots of debugging by hand.

        Adds Redirect directive to the port 80 equivalent of ssl_vhost
        First the function attempts to find the vhost with equivalent
        ip addresses that serves on non-ssl ports
        The function then adds the directive

        .. note:: This function saves the configuration

        :param ssl_vhost: Destination of traffic, an ssl enabled vhost
        :type ssl_vhost: :class:`~letsencrypt_apache.obj.VirtualHost`

        :param unused_options: Not currently used
        :type unused_options: Not Available

        :returns: Success, general_vhost (HTTP vhost)
        :rtype: (bool, :class:`~letsencrypt_apache.obj.VirtualHost`)

        """
        if not self.mod_loaded("rewrite_module"):
            self.enable_mod("rewrite")

        general_v = self._general_vhost(ssl_vhost)
        if general_v is None:
            # Add virtual_server with redirect
            logger.debug(
                "Did not find http version of ssl virtual host... creating")
            return self._create_redirect_vhost(ssl_vhost)
        else:
            # Check if redirection already exists
            exists, code = self._existing_redirect(general_v)
            if exists:
                if code == 0:
                    logger.debug("Redirect already added")
                    logger.info(
                        "Configuration is already redirecting traffic to HTTPS"
                    )
                    return
                else:
                    logger.info("Unknown redirect exists for this vhost")
                    raise errors.PluginError("Unknown redirect already exists "
                                             "in {}".format(general_v.filep))
            # Add directives to server
            self.parser.add_dir(general_v.path, "RewriteEngine", "On")
            self.parser.add_dir(general_v.path, "RewriteRule",
                                constants.REWRITE_HTTPS_ARGS)
            self.save_notes += ("Redirecting host in %s to ssl vhost in %s\n" %
                                (general_v.filep, ssl_vhost.filep))
            self.save()

            logger.info("Redirecting vhost in %s to ssl vhost in %s",
                        general_v.filep, ssl_vhost.filep)
Ejemplo n.º 18
0
    def prepare(self):  # pylint: disable=missing-docstring
        path = self.conf("path")
        if path is None:
            raise errors.PluginError("--{0} must be set".format(
                self.option_name("path")))
        if not os.path.isdir(path):
            raise errors.PluginError(path +
                                     " does not exist or is not a directory")
        self.full_root = os.path.join(path, challenges.HTTP01.URI_ROOT_PATH)

        logger.debug("Creating root challenges validation dir at %s",
                     self.full_root)
        try:
            os.makedirs(self.full_root)
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise errors.PluginError(
                    "Couldn't create root for http-01 "
                    "challenge responses: {0}", exception)
Ejemplo n.º 19
0
    def revert_challenge_config(self):
        """Used to cleanup challenge configurations.

        :raises .errors.PluginError: If unable to revert the challenge config.

        """
        try:
            self.reverter.revert_temporary_config()
        except errors.ReverterError as err:
            raise errors.PluginError(str(err))
        self.aug.load()
Ejemplo n.º 20
0
    def view_config_changes(self):
        """Show all of the configuration changes that have taken place.

        :raises .errors.PluginError: If there is a problem while processing
            the checkpoints directories.

        """
        try:
            self.reverter.view_config_changes()
        except errors.ReverterError as err:
            raise errors.PluginError(str(err))
Ejemplo n.º 21
0
    def recovery_routine(self):
        """Revert all previously modified files.

        Reverts all modified files that have not been saved as a checkpoint

        :raises .errors.PluginError: If unable to recover the configuration

        """
        try:
            self.reverter.recovery_routine()
        except errors.ReverterError as err:
            raise errors.PluginError(str(err))
        self.parser.load()
Ejemplo n.º 22
0
def _validate_webroot(webroot_path):
    """Validates and returns the absolute path of webroot_path.

    :param str webroot_path: path to the webroot directory

    :returns: absolute path of webroot_path
    :rtype: str

    """
    if not os.path.isdir(webroot_path):
        raise errors.PluginError(webroot_path + " does not exist or is not a directory")

    return os.path.abspath(webroot_path)
Ejemplo n.º 23
0
    def save(self, title=None, temporary=False):
        """Saves all changes to the configuration files.

        :param str title: The title of the save. If a title is given, the
            configuration will be saved as a new checkpoint and put in a
            timestamped directory.

        :param bool temporary: Indicates whether the changes made will
            be quickly reversed in the future (ie. challenges)

        :raises .errors.PluginError: If there was an error in
            an attempt to save the configuration, or an error creating a
            checkpoint

        """
        save_files = set(self.parser.parsed.keys())

        try:
            # Create Checkpoint
            if temporary:
                self.reverter.add_to_temp_checkpoint(
                    save_files, self.save_notes)
            else:
                self.reverter.add_to_checkpoint(save_files,
                                            self.save_notes)
        except errors.ReverterError as err:
            raise errors.PluginError(str(err))

        self.save_notes = ""

        # Change 'ext' to something else to not override existing conf files
        self.parser.filedump(ext='')
        if title and not temporary:
            try:
                self.reverter.finalize_checkpoint(title)
            except errors.ReverterError as err:
                raise errors.PluginError(str(err))

        return True
Ejemplo n.º 24
0
    def choose_vhost(self, target_name):
        """Chooses a virtual host based on the given domain name.

        If there is no clear virtual host to be selected, the user is prompted
        with all available choices.

        :param str target_name: domain name

        :returns: ssl vhost associated with name
        :rtype: :class:`~letsencrypt_apache.obj.VirtualHost`

        :raises .errors.PluginError: If no vhost is available

        """
        # Allows for domain names to be associated with a virtual host
        # Client isn't using create_dn_server_assoc(self, dn, vh) yet
        if target_name in self.assoc:
            return self.assoc[target_name]
        # Check for servernames/aliases for ssl hosts
        for vhost in self.vhosts:
            if vhost.ssl and target_name in vhost.names:
                self.assoc[target_name] = vhost
                return vhost
        # Checking for domain name in vhost address
        # This technique is not recommended by Apache but is technically valid
        target_addr = common.Addr((target_name, "443"))
        for vhost in self.vhosts:
            if target_addr in vhost.addrs:
                self.assoc[target_name] = vhost
                return vhost

        # Check for non ssl vhosts with servernames/aliases == "name"
        for vhost in self.vhosts:
            if not vhost.ssl and target_name in vhost.names:
                vhost = self.make_vhost_ssl(vhost)
                self.assoc[target_name] = vhost
                return vhost

        vhost = display_ops.select_vhost(target_name, self.vhosts)
        if vhost is not None:
            self.assoc[target_name] = vhost
        else:
            logger.error(
                "No vhost exists with servername or alias of: %s. "
                "No vhost was selected. Please specify servernames "
                "in the Apache config", target_name)
            raise errors.PluginError("No vhost selected")

        # TODO: Ask the user if they would like to add ServerName/Alias to VH

        return vhost
Ejemplo n.º 25
0
    def get_version(self):
        """Return version of Apache Server.

        Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7))

        :returns: version
        :rtype: tuple

        :raises .PluginError: if unable to find Apache version

        """
        try:
            stdout, _ = le_util.run_script([self.conf("ctl"), "-v"])
        except errors.SubprocessError:
            raise errors.PluginError("Unable to run %s -v" % self.conf("ctl"))

        regex = re.compile(r"Apache/([0-9\.]*)", re.IGNORECASE)
        matches = regex.findall(stdout)

        if len(matches) != 1:
            raise errors.PluginError("Unable to find Apache version")

        return tuple([int(i) for i in matches[0].split(".")])
Ejemplo n.º 26
0
    def prepare(self):
        """Prepare the plugin

        Get apikey and store in config
        """

        self.api_key = self._api_key_from_args() or\
            self._api_key_from_env() or\
            self._api_key_from_gandi_cli()

        if not self.api_key:
            raise errors.PluginError("Api key is missing, couldn't found from "
                                     "neither gandi.cli, environment"
                                     "(GANDI_API_KEY), nor --{0}".format(
                                         self.option_name('api-key')))

        self.shs_name = self.conf('name')
        if not self.shs_name:
            raise errors.PluginError("--{0} is a required parameter,"
                                     "please provide a valid simple hosting "
                                     "name".format(self.option_name('name')))

        self.vhost = self.conf('vhost')
Ejemplo n.º 27
0
    def rollback_checkpoints(self, rollback=1):
        """Rollback saved checkpoints.

        :param int rollback: Number of checkpoints to revert

        :raises .errors.PluginError: If there is a problem with the input or
            the function is unable to correctly revert the configuration

        """
        try:
            self.reverter.rollback_checkpoints(rollback)
        except errors.ReverterError as err:
            raise errors.PluginError(str(err))
        self.aug.load()
Ejemplo n.º 28
0
    def __call__(self, parser, namespace, webroot_path, option_string=None):
        if self._domain_before_webroot:
            raise errors.PluginError(
                "If you specify multiple webroot paths, "
                "one of them must precede all domain flags")

        if namespace.webroot_path:
            # Apply previous webroot to all matched
            # domains before setting the new webroot path
            prev_webroot = namespace.webroot_path[-1]
            for domain in namespace.domains:
                namespace.webroot_map.setdefault(domain, prev_webroot)
        elif namespace.domains:
            self._domain_before_webroot = True

        namespace.webroot_path.append(_validate_webroot(webroot_path))
Ejemplo n.º 29
0
    def deploy_cert(self,
                    domain,
                    cert_path,
                    key_path,
                    chain_path=None,
                    fullchain_path=None):

        if not fullchain_path:
            raise errors.PluginError(
                "The proxmox plugin currently requires --fullchain-path to "
                "install a cert.")
        logger.info("Copy certificate")

        copyfile(key_path, os.path.join(self.conf("location"), "pve-ssl.key"))
        copyfile(fullchain_path,
                 os.path.join(self.conf("location"), "pve-ssl.pem"))
Ejemplo n.º 30
0
 def assign_cert(self):
     """Assign certificate to the domain and enable SSL."""
     request = {
         'packet': {
             'site': {
                 'set': [{
                     'filter': {
                         'name': self.domain
                     }
                 }, {
                     'values': {
                         'hosting': {
                             'vrt_hst': [
                                 {
                                     'property': [
                                         {
                                             'name': 'ssl'
                                         },
                                         {
                                             'value': 'true'
                                         },
                                     ]
                                 },
                                 {
                                     'property': [
                                         {
                                             'name': 'certificate_name'
                                         },
                                         {
                                             'value': self.cert_name()
                                         },
                                     ]
                                 },
                             ]
                         }
                     }
                 }]
             }
         }
     }
     response = self.plesk_api_client.request(request)
     api_result = response['packet']['site']['set']['result']
     if 'ok' != api_result['status']:
         error_text = str(api_result['errtext'])
         raise errors.PluginError('Assign certificate failure: %s' %
                                  error_text)
     self.cert_assigned = True