Skip to content

Commit

Permalink
Fix SSL issues
Browse files Browse the repository at this point in the history
  • Loading branch information
darrenburns committed Jul 17, 2024
1 parent 4ab6b94 commit b93c396
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 28 deletions.
32 changes: 20 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,24 +230,23 @@ Dotenv files are separate from collections, although you may wish to include the
| `pager` (`POSTING_PAGER`) | (Default: `$PAGER`) | Command to use for paging text. |
| `pager_json` (`POSTING_PAGER_JSON`) | (Default: `$PAGER`) | Command to use for paging JSON. |
| `editor` (`POSTING_EDITOR`) | (Default: `$EDITOR`) | Command to use for opening files in an external editor. |
| `ssl.verify` (`POSTING_SSL__VERIFY`) | `true`, `false` (Default: `true`) | If enabled, SSL certificates will be verified. |
| `ssl.certificate_path` (`POSTING_SSL__CERTIFICATE_PATH`) | Absolute path (Default: `unset`) | Absolute path to the SSL certificate file or directory. |
| `ssl.key_file` (`POSTING_SSL__KEY_FILE`) | Absolute path (Default: `unset`) | Absolute path to the SSL key file. |
| `ssl.ca_bundle` (`POSTING_SSL__CA_BUNDLE`) | Absolute path (Default: `unset`) | Absolute path to a CA bundle file/dir. If not set, the [Certifi](https://pypi.org/project/certifi/) CA bundle will be used. |
| `ssl.verify` (`POSTING_SSL__VERIFY`) | `true`, `false` (Default: `true`) | Verify server identity. |
| `ssl.certificate_path` (`POSTING_SSL__CERTIFICATE_PATH`) | Absolute path (Default: `unset`) | Absolute path to a client SSL certificate file or directory. |
| `ssl.key_file` (`POSTING_SSL__KEY_FILE`) | Absolute path (Default: `unset`) | Absolute path to a client SSL key file. |
| `ssl.password` (`POSTING_SSL__PASSWORD`) | Password for the key file. (Default: `unset`) | Password to decrypt the key file if it's encrypted. |
| `focus.on_startup` (`POSTING_FOCUS__ON_STARTUP`) | `"url"`, `"method", "collection"` (Default: `"url"`) | Automatically focus the URL bar, method, or collection browser when the app starts. |
| `focus.on_response` (`POSTING_FOCUS__ON_RESPONSE`) | `"body"`, `"tabs"` (Default: `unset`)| Automatically focus the response tabs or response body text area when a response is received. |

## Loading SSL certificates
## SSL certificate configuration

Posting can load SSL certificates from a `.pem` file or directory.
Posting can load custom CA bundles from a `.pem` file.

The easiest way to do this is in your `config.yaml` file:

```yaml
ssl:
certificate_path: 'absolute/path/to/certificate.pem'
key_file: 'absolute/path/to/key.key'
password: '***********'
ca_bundle: 'absolute/path/to/certificate.pem'
```

### Environment-specific certificates
Expand All @@ -256,17 +255,26 @@ If the required CA bundle differs per environment, you can again use the princip

```bash
# dev.env
POSTING_SSL__CERTIFICATE_PATH='/path/to/certificate.pem'
POSTING_SSL__KEY_FILE='/path/to/key.key'
POSTING_SSL__PASSWORD='***********'
POSTING_SSL__CA_BUNDLE='/path/to/certificate.pem'
```

Now load the `dev.env` file when working in the `dev` environment to ensure the dev environment certificate is used:
Now load the `dev.env` file when working in the `dev` environment to ensure the dev environment CA bundle is used:

```bash
posting --env dev.env
```

### Client-side certificates

You can specify local certificates to use as a client-side certificate:

```yaml
ssl:
certificate_path: /path/to/certificate.pem
key_file: /path/to/key.key # optional
password: '***********' # optional password for key_file
```

## Importing OpenAPI Specifications

Note: this feature is highly experimental.
Expand Down
20 changes: 19 additions & 1 deletion sample-collections/echo-post.posting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,23 @@ url: https://postman-echo.com/post
body:
content: |-
{
"another": "$TERM_PROGRAM",
"term_program": "$TERM_PROGRAM",
}
headers:
- name: Content-Type
value: application/json
- name: Accept
value: '*'
- name: Cache-Control
value: no-cache
- name: Accept-Encoding
value: gzip
params:
- name: key1
value: value1
- name: another-key
value: another-value
- name: number
value: '123'
options:
timeout: 0.2
28 changes: 17 additions & 11 deletions src/posting/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,25 @@ async def send_request(self) -> None:
timeout = request_options.timeout
auth = self.request_auth.to_httpx_auth()

ca_config = SETTINGS.get().ssl
cert_config: list[str] = []
if certificate_path := ca_config.certificate_path:
cert_config.append(certificate_path)
if key_file := ca_config.key_file:
cert_config.append(key_file)
if password := ca_config.password:
cert_config.append(password.get_secret_value())

cert = cast(CertTypes, tuple(cert_config))
cert_config = SETTINGS.get().ssl
httpx_cert_config: list[str] = []
if certificate_path := cert_config.certificate_path:
httpx_cert_config.append(certificate_path)
if key_file := cert_config.key_file:
httpx_cert_config.append(key_file)
if password := cert_config.password:
httpx_cert_config.append(password.get_secret_value())

verify: str | bool = verify_ssl
if verify_ssl and cert_config.ca_bundle is not None:
# If verification is enabled and a CA bundle is supplied,
# use the CA bundle.
verify = cert_config.ca_bundle

cert = cast(CertTypes, tuple(httpx_cert_config))
try:
async with httpx.AsyncClient(
verify=verify_ssl,
verify=verify,
cert=cert,
proxy=proxy_url,
timeout=timeout,
Expand Down
10 changes: 6 additions & 4 deletions src/posting/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ class FocusSettings(BaseModel):


class CertificateSettings(BaseModel):
"""Configuration for SSL CA bundles"""
"""Configuration for SSL CA bundles and client certificates."""

ca_bundle: str | None = Field(default=None)
"""Absolute path to the CA bundle file."""
certificate_path: str | None = Field(default=None)
"""Path to the certificate .pem file or directory"""
"""Absolute path to the certificate .pem file or directory"""
key_file: str | None = Field(default=None)
"""Path to the key file"""
"""Absolute path to the key file"""
password: SecretStr | None = Field(default=None)
"""Password for the key file."""

Expand Down Expand Up @@ -113,7 +115,7 @@ class Settings(BaseSettings):
"""The command to use for editing."""

ssl: CertificateSettings = Field(default_factory=CertificateSettings)
"""Configuration for SSL CA bundle."""
"""Configuration for SSL CA bundle and client certificates."""

focus: FocusSettings = Field(default_factory=FocusSettings)
"""Configuration for focus."""
Expand Down

0 comments on commit b93c396

Please sign in to comment.