├── .gitignore ├── LICENSE ├── README.md ├── configurator.py └── powershell.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Felix Rieseberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The work here has moved 2 | After discussion with the Let's Encrypt team, we'll work to include the IIS plugin with the main repository. For that reason, our work has moved to https://github.com/felixrieseberg/lets-encrypt-preview/tree/iis and the main repo at https://github.com/letsencrypt/lets-encrypt-preview. 3 | -------------------------------------------------------------------------------- /configurator.py: -------------------------------------------------------------------------------- 1 | """IIS Configuration""" 2 | import logging 3 | import os 4 | import re 5 | import shutil 6 | import socket 7 | import subprocess 8 | import sys 9 | 10 | import zope.interface 11 | 12 | from letsencrypt.acme import challenges 13 | 14 | from letsencrypt.client import achallenges 15 | from letsencrypt.client import constants 16 | from letsencrypt.client import errors 17 | from letsencrypt.client import interfaces 18 | from letsencrypt.client import le_util 19 | from letsencrypt.client import reverter 20 | 21 | class IISConfigurator(object): 22 | # pylint: disable=too-many-instance-attributes,too-many-public-methods 23 | """IIS configurator. 24 | 25 | .. warning:: This plugin is a stub! 26 | 27 | :ivar config: Configuration. 28 | :type config: :class:`~letsencrypt.client.interfaces.IConfig` 29 | 30 | :ivar str save_notes: Human-readable config change notes 31 | 32 | :ivar reverter: saves and reverts checkpoints 33 | :type reverter: :class:`letsencrypt.client.reverter.Reverter` 34 | 35 | """ 36 | zope.interface.implements(interfaces.IAuthenticator, interfaces.IInstaller) 37 | 38 | description = "IIS" 39 | 40 | def __init__(self, config): 41 | """Initialize an IIS Configurator. 42 | """ 43 | self.config = config 44 | 45 | def prepare(): 46 | """Prepare the installer. 47 | 48 | Finish up any additional initialization. 49 | 50 | :raises letsencrypt.client.errors.LetsEncryptMisconfigurationError`: 51 | when full initialization cannot be completed. 52 | :raises letsencrypt.errors.LetsEncryptNoInstallationError`: 53 | when the necessary programs/files cannot be located. 54 | 55 | """ 56 | 57 | def get_all_names(): 58 | """Returns all names that may be authenticated.""" 59 | 60 | def deploy_cert(domain, cert, key, cert_chain=None): 61 | """Deploy certificate. 62 | 63 | :param str domain: domain to deploy certificate 64 | :param str cert: certificate filename 65 | :param str key: private key filename 66 | 67 | """ 68 | 69 | def enhance(domain, enhancement, options=None): 70 | """Perform a configuration enhancement. 71 | 72 | :param str domain: domain for which to provide enhancement 73 | :param str enhancement: An enhancement as defined in 74 | :const:`~letsencrypt.client.constants.ENHANCEMENTS` 75 | :param options: Flexible options parameter for enhancement. 76 | Check documentation of 77 | :const:`~letsencrypt.client.constants.ENHANCEMENTS` 78 | for expected options for each enhancement. 79 | 80 | """ 81 | 82 | def supported_enhancements(): 83 | """Returns a list of supported enhancements. 84 | 85 | :returns: supported enhancements which should be a subset of 86 | :const:`~letsencrypt.client.constants.ENHANCEMENTS` 87 | :rtype: :class:`list` of :class:`str` 88 | 89 | """ 90 | 91 | def get_all_certs_keys(): 92 | """Retrieve all certs and keys set in configuration. 93 | 94 | :returns: tuples with form `[(cert, key, path)]`, where: 95 | 96 | - `cert` - str path to certificate file 97 | - `key` - str path to associated key file 98 | - `path` - file path to configuration file 99 | 100 | :rtype: list 101 | 102 | """ 103 | 104 | def save(title=None, temporary=False): 105 | """Saves all changes to the configuration files. 106 | 107 | Both title and temporary are needed because a save may be 108 | intended to be permanent, but the save is not ready to be a full 109 | checkpoint 110 | 111 | :param str title: The title of the save. If a title is given, the 112 | configuration will be saved as a new checkpoint and put in a 113 | timestamped directory. `title` has no effect if temporary is true. 114 | 115 | :param bool temporary: Indicates whether the changes made will 116 | be quickly reversed in the future (challenges) 117 | 118 | """ 119 | 120 | def rollback_checkpoints(rollback=1): 121 | """Revert `rollback` number of configuration checkpoints.""" 122 | 123 | def view_config_changes(): 124 | """Display all of the LE config changes.""" 125 | 126 | def config_test(): 127 | """Make sure the configuration is valid.""" 128 | 129 | def restart(): 130 | """Restart or refresh the server content.""" 131 | 132 | ##------------------------------------------------------------------------------- 133 | # IAuthenticator 134 | ##------------------------------------------------------------------------------- 135 | 136 | def get_chall_pref(domain): 137 | """Return list of challenge preferences. 138 | 139 | :param str domain: Domain for which challenge preferences are sought. 140 | 141 | :returns: List of challege types (subclasses of 142 | :class:`letsencrypt.acme.challenges.Challenge`) with the most 143 | preferred challenges first. If a type is not specified, it means the 144 | Authenticator cannot perform the challenge. 145 | :rtype: list 146 | 147 | """ 148 | 149 | def perform(achalls): 150 | """Perform the given challenge. 151 | 152 | :param list achalls: Non-empty (guaranteed) list of 153 | :class:`~letsencrypt.client.achallenges.AnnotatedChallenge` 154 | instances, such that it contains types found within 155 | :func:`get_chall_pref` only. 156 | 157 | :returns: List of ACME 158 | :class:`~letsencrypt.acme.challenges.ChallengeResponse` instances 159 | or if the :class:`~letsencrypt.acme.challenges.Challenge` cannot 160 | be fulfilled then: 161 | 162 | ``None`` 163 | Authenticator can perform challenge, but not at this time. 164 | ``False`` 165 | Authenticator will never be able to perform (error). 166 | 167 | :rtype: :class:`list` of 168 | :class:`letsencrypt.acme.challenges.ChallengeResponse` 169 | 170 | """ 171 | 172 | def cleanup(achalls): 173 | """Revert changes and shutdown after challenges complete. 174 | 175 | :param list achalls: Non-empty (guaranteed) list of 176 | :class:`~letsencrypt.client.achallenges.AnnotatedChallenge` 177 | instances, a subset of those previously passed to :func:`perform`. 178 | 179 | """ 180 | 181 | def more_info(): 182 | """Human-readable string to help the user. 183 | 184 | Should describe the steps taken and any relevant info to help the user 185 | decide which Authenticator to use. 186 | 187 | """ -------------------------------------------------------------------------------- /powershell.py: -------------------------------------------------------------------------------- 1 | import subprocess, sys 2 | 3 | class IISPowerShell: 4 | def run(script): 5 | """Run a PowerShell Script 6 | 7 | :param str script: path to script 8 | """ 9 | 10 | p = subprocess.Popen(["powershell.exe", script], stdout=sys.stdout) 11 | --------------------------------------------------------------------------------