Skip to content

Commit 1c047c8

Browse files
authored
Merge pull request #640 from marle3003/develop
Develop
2 parents c11fba1 + 5c82e1a commit 1c047c8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1599
-296
lines changed

acceptance/mail/config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ servers:
55
smtps:
66
host: localhost:8025
77
protocol: smtps
8+
customImaps:
9+
host: mail.mokapi.local:8993
10+
protocol: imaps
11+
dynamicImaps:
12+
host: imap.mokapi.local:8994
13+
protocol: imaps
814
rules:
915
allowSender:
1016
sender: .*@foo.bar
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDGTCCAgGgAwIBAgIUPA/srixlfc1AdBYDnnbzFP6qt4EwDQYJKoZIhvcNAQEL
3+
BQAwHDEaMBgGA1UEAwwRbWFpbC5tb2thcGkubG9jYWwwHhcNMjUwODEwMTA1ODE1
4+
WhcNMjYwODEwMTA1ODE1WjAcMRowGAYDVQQDDBFtYWlsLm1va2FwaS5sb2NhbDCC
5+
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJsLN8dxH41tNdwEOcQiL6SM
6+
Rtsx1vB852YhSGZ2Vbe3jGVFJLEG2O8VxrC1FF5qD5deCWwJ1c+E2i85TdvuqOpD
7+
r6+LWxkwSxYFhHzfALQNwj/70arTjSZ/QqOU5vPAs6GrsBKmGMmhKoEBuem/OQ7m
8+
Vt8HcW2z0mvt6ZsJlev1i6ry2pqoJYe2b97XTa+93XmuIDXQnQoAW4iXinXWgN37
9+
2t8ihw66vYlLk9l05PX8jnT+G2JqkxUaBqatE9wr1nQAbUfFjJl+OuniUMNZ6aBZ
10+
mAoVoAW9w/YrKnYDsrwnuByyoxSkpzWdUO5gUIMmp8zbBkUserchIiPusG6juocC
11+
AwEAAaNTMFEwHQYDVR0OBBYEFLbkG5lNinmCae1AxQQbZqs/8nGzMB8GA1UdIwQY
12+
MBaAFLbkG5lNinmCae1AxQQbZqs/8nGzMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
13+
hvcNAQELBQADggEBAHNjC037c9jeODLFGBK+/M43NU4EbU0b1omY25C5jjdMZeV6
14+
WRJNfC/EgOPzjZbykAJre5nKaT+jR1ITWtz8zb2sziAan3Ce9zcjwHBiFmblK2EW
15+
yiqorhW/xyYrk3b59dAypIvQIRAvZ53cflOiL1erGiD5WxIjSDouKfxkjkIF9yOQ
16+
VheX0KCIB7KqXkP3gb/LWXbZspRa9LgWZbo/+Rc/X4VISyTVOvNHVS9HQVLBXy59
17+
Qo8zxcCYPBw29TPdawhc7iR2J3FZKOZrq0ZY6UuWDuGiOI2AJ/Qnqp9cF/vmVjF5
18+
cTrB0VcoyMXCcUwTCSY7IpVWt9OJU7SqbdnWJdM=
19+
-----END CERTIFICATE-----
20+
-----BEGIN PRIVATE KEY-----
21+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbCzfHcR+NbTXc
22+
BDnEIi+kjEbbMdbwfOdmIUhmdlW3t4xlRSSxBtjvFcawtRReag+XXglsCdXPhNov
23+
OU3b7qjqQ6+vi1sZMEsWBYR83wC0DcI/+9Gq040mf0KjlObzwLOhq7ASphjJoSqB
24+
AbnpvzkO5lbfB3Fts9Jr7embCZXr9Yuq8tqaqCWHtm/e102vvd15riA10J0KAFuI
25+
l4p11oDd+9rfIocOur2JS5PZdOT1/I50/htiapMVGgamrRPcK9Z0AG1HxYyZfjrp
26+
4lDDWemgWZgKFaAFvcP2Kyp2A7K8J7gcsqMUpKc1nVDuYFCDJqfM2wZFLHq3ISIj
27+
7rBuo7qHAgMBAAECggEABFvf4RUOmIjJ+1oJD7kQUtV4xn/TtaYlUUs9QFgyV7xq
28+
z4wOmIWDQtF/aQdmP7NGpfBIXoe2QaPQCITZagX/LLrjbRGDaaVgbwmPrH0OhYFf
29+
hTH8totFDCCGzJeKmK7BvhlYFWYjC0QjMEZOpkIwhfk21wVcDIQCNfOV3jx6QQx2
30+
f5W/Sjjv4HY2rRvNVI01DfucOvP1Ekovh3iD+n1A+LkhUP+7UnWMnW/+Z01oUW93
31+
3yaVZjBUbCIC3eoMG3H9RiNXXTdIwQnjKcIX/MeF5sZ6DA0abi5jQ8FUHLGche4w
32+
xG6xU0zlz02xQ7fsVmqKfCoNlsDQsmhDK6+OoqVNqQKBgQDOn2FuU/LaYE491xUd
33+
/65Hgp5MDpdIoPYwVjl0wudgEy9Vm03+cR9FqPoL3PKkmXweYeSTLVTI2Qj8HBA1
34+
Ak3JJ8CcUDASmhJXXhVgXbBuohpnKGq6Aq2/8dgC+/4mRBaL8zstJd9IDmkAK67j
35+
LQbTjw9CewFgRUaBTv9hXTePeQKBgQDAGGLTTj+8MnC4nri/KlMG97vPErQ4YRWW
36+
TI1DM6Gapa/2aj2q+ikKHTqyh+S+isyI/4PijRKl+d6+jPyZLD8SfY68HjBmkg4B
37+
d8Hb671BJud5VfDbsNWZJqFllJkTGQBVRYnVqhpRt6JHQWG8fGttU5rAsMFgKZwp
38+
xBdZUlEZ/wKBgDdQsdvAe658w9WIZC3gyj54uHoyGcwm02HDY6RfnWO6Hxzy8+Ff
39+
VXjnsPFGGGt6b6EOogvIwf73I5Giza/zSvHEQ6tVSFlih/B9zok668XifeEKD/B2
40+
UR+m1iaOYc7KwaJ73mbK0cjPmsqh5zMIVeCDVxl8JrUoNqTdij79nqc5AoGBAIrN
41+
VCNxSBZ5r/+HGOFw+LtxKHDRCA4xAIMw32Xumdf/3uzECblQt3TKeA5mqT+RVYes
42+
caSy4QWzTmMLxr37Pbvjo86EVd7XrG0dFqQNbBv2u41uLvLfjQfz5O1ceVtWVmpH
43+
K/iKyCfB8+1e7ftfP9Soc4rGbYRJrMB1I5X0KAwLAoGAIkAohY5unXmUw+ueSUtm
44+
M7mN6/apNQzmXCk/aBOscz6HbQoFzVm2vNaXjT5ZfCoJI+1KMocMfD52CK568ode
45+
wRF/gG1/Z8fUH219z/VyS9UZ8MwQj0ZGdZpKCpt5Ce+ijSdRzoJmZ4A4p/l2fzPA
46+
Vg7m4v6VowVMbbBjczJT8ws=
47+
-----END PRIVATE KEY-----

acceptance/mail_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
package acceptance
22

33
import (
4+
"crypto/tls"
45
"encoding/json"
56
"github.com/stretchr/testify/require"
67
"mokapi/config/static"
78
"mokapi/server/cert"
89
"mokapi/smtp/smtptest"
910
"mokapi/try"
11+
"net"
12+
"os"
13+
"path"
1014
"testing"
1115
)
1216

1317
type MailSuite struct{ BaseSuite }
1418

1519
func (suite *MailSuite) SetupSuite() {
1620
cfg := static.NewConfig()
21+
wd, err := os.Getwd()
22+
require.NoError(suite.T(), err)
23+
cfg.ConfigFile = path.Join(wd, "mokapi.yaml")
1724
cfg.Providers.File.Directories = []string{"./mail"}
25+
cfg.Certificates.Static = []static.Certificate{
26+
{Cert: "./mail/mail.mokapi.local.pem"},
27+
}
1828
suite.initCmd(cfg)
1929
}
2030

@@ -238,3 +248,52 @@ It can be any text data.
238248
}),
239249
)
240250
}
251+
252+
func (suite *MailSuite) TestCustomServerCertificate() {
253+
conn, err := net.Dial("tcp", "localhost:8993")
254+
require.NoError(suite.T(), err)
255+
defer func() { _ = conn.Close() }()
256+
257+
// Upgrade to TLS
258+
tlsConn := tls.Client(conn, &tls.Config{
259+
// triggers hostname verification
260+
ServerName: "mail.mokapi.local",
261+
InsecureSkipVerify: true,
262+
})
263+
defer func() { _ = tlsConn.Close() }()
264+
265+
err = tlsConn.Handshake()
266+
require.NoError(suite.T(), err)
267+
268+
// Get server certificate
269+
state := tlsConn.ConnectionState()
270+
require.Len(suite.T(), state.PeerCertificates, 1)
271+
c := state.PeerCertificates[0]
272+
273+
require.Equal(suite.T(), "mail.mokapi.local", c.Subject.CommonName)
274+
}
275+
276+
func (suite *MailSuite) TestDynamicServerCertificate() {
277+
conn, err := net.Dial("tcp", "localhost:8994")
278+
require.NoError(suite.T(), err)
279+
defer func() { _ = conn.Close() }()
280+
281+
// Upgrade to TLS
282+
tlsConn := tls.Client(conn, &tls.Config{
283+
// triggers hostname verification
284+
ServerName: "imap.mokapi.local",
285+
InsecureSkipVerify: true,
286+
})
287+
defer func() { _ = tlsConn.Close() }()
288+
289+
err = tlsConn.Handshake()
290+
require.NoError(suite.T(), err)
291+
292+
// Get server certificate
293+
state := tlsConn.ConnectionState()
294+
// root CA is included
295+
require.Greater(suite.T(), len(state.PeerCertificates), 1)
296+
c := state.PeerCertificates[0]
297+
298+
require.Equal(suite.T(), "imap.mokapi.local", c.Subject.CommonName)
299+
}

acceptance/petstore_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,14 @@ func (suite *PetStoreSuite) TestGetOrderById() {
187187
try.HasBody(`{"id":12545,"petId":20895,"quantity":16,"shipDate":"2027-11-26T16:57:16Z","status":"approved","complete":true}`))
188188
}
189189

190+
func (suite *PetStoreSuite) TestTls() {
191+
try.GetRequest(suite.T(), "https://localhost:18443/store/order/10",
192+
map[string]string{"Accept": "application/json"},
193+
try.HasStatusCode(http.StatusOK),
194+
try.IsTls("localhost"),
195+
)
196+
}
197+
190198
func (suite *PetStoreSuite) TestKafka_TopicConfig() {
191199
c := kafkatest.NewClient("127.0.0.1:19092", "test")
192200
defer c.Close()

bruno/mail/mailbox messages.bru

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@ meta {
55
}
66

77
get {
8-
url: {{baseUrl}}/services/mail/{{mailServerName}}/mailboxes/:mailbox/folders/:folder
8+
url: {{baseUrl}}/services/mail/{{mailServerName}}/mailboxes/:mailbox/messages
99
body: none
1010
auth: inherit
1111
}
1212

13+
params:query {
14+
~folder:
15+
~index:
16+
~limit:
17+
}
18+
1319
params:path {
14-
folder: INBOX
15-
20+
1621
}
1722

1823
settings {

cmd/mokapi/main_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ event:
6969
store:
7070
default:
7171
size: 100
72+
certificates:
73+
static: []
7274
`, out)
7375
},
7476
},

config/dynamic/mokapi/config.go

Lines changed: 0 additions & 21 deletions
This file was deleted.

config/static/static_config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Config struct {
2424
Features []string `json:"-" yaml:"-" explode:"feature"`
2525
Version bool `json:"-" yaml:"-" aliases:"v"`
2626
Event Event `json:"event" yaml:"event"`
27+
Certificates CertificateStore `json:"certificates" yaml:"certificates"`
2728
Args []string `json:"args" yaml:"-" aliases:"args"` // positional arguments
2829
}
2930

@@ -167,6 +168,15 @@ type Store struct {
167168

168169
type Configs []string
169170

171+
type CertificateStore struct {
172+
Static []Certificate
173+
}
174+
175+
type Certificate struct {
176+
Cert tls.FileOrContent `yaml:"cert" json:"cert"`
177+
Key tls.FileOrContent `yaml:"key" json:"key"`
178+
}
179+
170180
func (c *Configs) UnmarshalJSON(b []byte) error {
171181
dec := json.NewDecoder(bytes.NewReader(b))
172182
token, err := dec.Token()

docs/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"index": "guides/mail/overview.md",
3636
"items": {
3737
"Quick Start": "guides/mail/quick-start.md",
38+
"Client": "guides/mail/client.md",
3839
"Rules": "guides/mail/rules.md"
3940
}
4041
}

docs/guides/http/tls.md

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,83 @@
11
---
22
title: HTTPS, TLS and Certificates
3-
description: Mokapi is able to mock the behaviour of multiple hostnames and present a valid X.509 Certificate for them. This guide shows you how to configure TLS.
3+
description: Mokapi can mock the behaviour of multiple hostnames and present valid X.509 certificates for them. This guide explains how to configure TLS in Mokapi.
44
---
55
# HTTPS, TLS and Certificates
6-
Mokapi is able to mock the behaviour of multiple hostnames and present a valid X.509 Certificate
7-
for them. This guide shows you how to configure TLS.
6+
Mokapi can simulate multiple hostnames and present a valid X.509 certificate for each of
7+
them, making it possible to test HTTPS endpoints with realistic TLS behavior.
8+
This guide explains how TLS works in Mokapi and how you can configure certificates to suit
9+
your needs.
10+
11+
## Example: Mocking HTTPS Endpoints
12+
13+
When defining your API, you can specify HTTPS URLs in the `servers` section. Mokapi will
14+
automatically generate certificates for these hostnames at runtime if none are provided.
815

916
```yaml
1017
openapi: 3.0.0
11-
info: {}
18+
info:
19+
title: Petstore
20+
version: "1"
1221
servers:
1322
- url: https://demo
1423
- url: https://demo:8443
1524
paths: {}
1625
```
1726
18-
## Certificate Authority
19-
By default, Mokapi signs all generated certificate with its own CA certificate in the [git repo](https://github.com/marle3003/mokapi/tree/master/assets).
27+
In this example:
28+
- Mokapi will respond over HTTPS for https://demo and https://demo:8443.
29+
- If no certificate is provided, Mokapi will generate one signed by its own Certificate Authority.
2030
21-
This example demonstrates how to reference a custom CA certificate as an environment variable.
31+
## Certificate Authority (CA)
32+
By default, Mokapi uses its own built-in Certificate Authority to sign any certificates it
33+
generates. The Root CA certificate and key are stored in the [Mokapi GitHub repository](https://github.com/marle3003/mokapi/tree/master/assets).
34+
35+
If you want to use your own CA for signing, you can specify it, for example, by setting environment variables.
2236
```yaml
2337
MOKAPI_RootCaCert: /path/to/caCert.pem
2438
MOKAPI_RootCaKey: /path/to/caKey.pem
2539
```
2640
27-
## Server Certificate
28-
You can set your custom server certificate or let Mokapi generate it on runtime. Mokapi
29-
generates a new certificate at first request, if you not provide a suitable certificate.
41+
Why use your own CA?
42+
- To avoid browser or client certificate warnings (if your CA is trusted by the OS or application).
43+
- To align with an existing internal PKI (Public Key Infrastructure).
44+
- To test certificate chains with your organization’s security policies.
45+
46+
## Server Certificates
47+
48+
Mokapi supports two ways of providing server certificates:
49+
50+
### Option A — Let Mokapi Generate Certificates
51+
52+
If you do not supply a certificate for a hostname, Mokapi will generate one dynamically the first
53+
time that hostname is requested. The certificate will be valid for the requested hostname and
54+
signed by the configured CA (Mokapi’s default or your custom CA).
55+
56+
### Option B — Provide Your Own Certificates
57+
58+
If you already have certificates, you can configure Mokapi to use them instead of generating new ones.
59+
Add them to the static configuration:
3060
3161
```yaml
32-
mokapi: 1.0
3362
certificates:
34-
- certFile: ./domainCert.pem
35-
keyFile: ./domainKey.pem
36-
- certFile: /path/to/other-domain.cert
37-
keyFile: /path/to/other-domain.key
38-
```
63+
static:
64+
- cert: ./domainCert.pem
65+
key: ./domainKey.pem
66+
- cert: /path/to/other-domain.cert
67+
key: /path/to/other-domain.key
68+
```
69+
70+
You can list multiple certificate/key pairs to support multiple hostnames.
71+
72+
## Tips for Working with Certificates
73+
74+
- **Trust the CA** — If you use Mokapi’s default CA, importing its root certificate into your OS or browser’s trust store will prevent certificate warnings.
75+
- **Match Hostnames** — The certificate’s Common Name (CN) or Subject Alternative Name (SAN) must match the hostname in your API definition (servers list).
76+
- **Use Custom Domains** — For local testing, you can map custom domains in your /etc/hosts file or Windows hosts file to 127.0.0.1 so the hostname matches the certificate.
77+
78+
## Summary
79+
80+
- Mokapi can generate certificates dynamically or use certificates you provide.
81+
- Certificates are signed by Mokapi’s default CA unless you specify a custom one.
82+
- You can configure both the CA and the server certificates via environment variables or the static configuration.
83+
- Trusting the CA in your OS avoids browser or client security warnings.

0 commit comments

Comments
 (0)