Skip to content

Commit f60fcad

Browse files
committed
feat: back-channel logout request client tls configuration
1 parent 70e6fe9 commit f60fcad

File tree

6 files changed

+297
-9
lines changed

6 files changed

+297
-9
lines changed

consent/strategy_default.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
"strings"
2929
"time"
3030

31+
"github.com/ory/x/httpx"
32+
3133
"github.com/ory/hydra/driver/config"
3234

3335
"github.com/ory/x/errorsx"
@@ -60,17 +62,30 @@ const (
6062
)
6163

6264
type DefaultStrategy struct {
63-
c *config.DefaultProvider
64-
r InternalRegistry
65+
c *config.DefaultProvider
66+
r InternalRegistry
67+
httpClientOptions httpx.ResilientOptions
6568
}
6669

6770
func NewStrategy(
6871
r InternalRegistry,
6972
c *config.DefaultProvider,
7073
) *DefaultStrategy {
74+
httpClientTlsConfig, err := c.TLSClientConfigWithDefaultFallback(config.KeyPrefixClientBackChannelLogout)
75+
if err != nil {
76+
r.Logger().WithError(err).Fatalf("Unable to setup back-channel logout http client TLS configuration.")
77+
}
78+
httpClientOptions := httpx.ResilientClientWithClient(&http.Client{
79+
Timeout: time.Minute,
80+
Transport: &http.Transport{
81+
Proxy: http.ProxyFromEnvironment,
82+
TLSClientConfig: httpClientTlsConfig,
83+
},
84+
})
7185
return &DefaultStrategy{
72-
c: c,
73-
r: r,
86+
c: c,
87+
r: r,
88+
httpClientOptions: httpClientOptions,
7489
}
7590
}
7691

@@ -674,7 +689,7 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http.
674689
WithField("client_id", t.clientID).
675690
WithField("backchannel_logout_url", t.url)
676691

677-
res, err := s.r.HTTPClient(ctx).PostForm(t.url, url.Values{"logout_token": {t.token}})
692+
res, err := s.r.HTTPClient(ctx, s.httpClientOptions).PostForm(t.url, url.Values{"logout_token": {t.token}})
678693
if err != nil {
679694
log.WithError(err).Error("Unable to execute OpenID Connect Back-Channel Logout Request")
680695
return

driver/config/tls.go

+70
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ package config
33
import (
44
"context"
55
"crypto/tls"
6+
"fmt"
7+
"strings"
68

9+
"github.com/hashicorp/go-secure-stdlib/tlsutil"
710
"github.com/pkg/errors"
811

912
"github.com/ory/x/logrusx"
@@ -24,6 +27,35 @@ const (
2427
KeyTLSCertPath = "serve." + KeySuffixTLSCertPath
2528
KeyTLSKeyPath = "serve." + KeySuffixTLSKeyPath
2629
KeyTLSEnabled = "serve." + KeySuffixTLSEnabled
30+
31+
KeyClientTLSInsecureSkipVerify = "tls.insecure_skip_verify"
32+
KeySuffixClientTLSCipherSuites = "tls.cipher_suites"
33+
KeySuffixClientTLSMinVer = "tls.min_version"
34+
KeySuffixClientTLSMaxVer = "tls.max_version"
35+
)
36+
37+
type ClientInterface interface {
38+
Key(suffix string) string
39+
}
40+
41+
func (iface *clientPrefix) Key(suffix string) string {
42+
return fmt.Sprintf("%s.%s", iface.prefix, suffix)
43+
}
44+
45+
type clientPrefix struct {
46+
prefix string
47+
}
48+
49+
var (
50+
KeyPrefixClientDefault ClientInterface = &clientPrefix{
51+
prefix: "client.default",
52+
}
53+
KeyPrefixClientBackChannelLogout ClientInterface = &clientPrefix{
54+
prefix: "client.back_channel_logout",
55+
}
56+
KeyPrefixClientRefreshTokenHook ClientInterface = &clientPrefix{
57+
prefix: "client.refresh_token_hook",
58+
}
2759
)
2860

2961
type TLSConfig interface {
@@ -63,6 +95,44 @@ func (p *DefaultProvider) TLS(ctx context.Context, iface ServeInterface) TLSConf
6395
}
6496
}
6597

98+
func (p *DefaultProvider) TLSClientConfigDefault() (*tls.Config, error) {
99+
return p.TLSClientConfigWithDefaultFallback(KeyPrefixClientDefault)
100+
}
101+
102+
func (p *DefaultProvider) TLSClientConfigWithDefaultFallback(iface ClientInterface) (*tls.Config, error) {
103+
tlsClientConfig := new(tls.Config)
104+
tlsClientConfig.InsecureSkipVerify = p.p.BoolF(KeyClientTLSInsecureSkipVerify, false)
105+
106+
if p.p.Exists(KeyPrefixClientDefault.Key(KeySuffixClientTLSCipherSuites)) || p.p.Exists(iface.Key(KeySuffixClientTLSCipherSuites)) {
107+
keyCipherSuites := p.p.StringsF(iface.Key(KeySuffixClientTLSCipherSuites), p.p.Strings(KeyPrefixClientDefault.Key(KeySuffixClientTLSCipherSuites)))
108+
cipherSuites, err := tlsutil.ParseCiphers(strings.Join(keyCipherSuites[:], ","))
109+
if err != nil {
110+
return nil, errors.WithMessage(err, "Unable to setup client TLS configuration")
111+
}
112+
tlsClientConfig.CipherSuites = cipherSuites
113+
}
114+
115+
if p.p.Exists(KeyPrefixClientDefault.Key(KeySuffixClientTLSMinVer)) || p.p.Exists(iface.Key(KeySuffixClientTLSMinVer)) {
116+
keyMinVer := p.p.StringF(iface.Key(KeySuffixClientTLSMinVer), p.p.String(KeyPrefixClientDefault.Key(KeySuffixClientTLSMinVer)))
117+
if tlsMinVer, found := tlsutil.TLSLookup[keyMinVer]; !found {
118+
return nil, errors.Errorf("Unable to setup client TLS configuration. Invalid minimum TLS version: %s", keyMinVer)
119+
} else {
120+
tlsClientConfig.MinVersion = tlsMinVer
121+
}
122+
}
123+
124+
if p.p.Exists(KeyPrefixClientDefault.Key(KeySuffixClientTLSMaxVer)) || p.p.Exists(iface.Key(KeySuffixClientTLSMaxVer)) {
125+
keyMaxVer := p.p.StringF(iface.Key(KeySuffixClientTLSMaxVer), p.p.String(KeyPrefixClientDefault.Key(KeySuffixClientTLSMaxVer)))
126+
if tlsMaxVer, found := tlsutil.TLSLookup[keyMaxVer]; !found {
127+
return nil, errors.Errorf("Unable to setup client TLS configuration. Invalid maximum TLS version: %s", keyMaxVer)
128+
} else {
129+
tlsClientConfig.MaxVersion = tlsMaxVer
130+
}
131+
}
132+
133+
return tlsClientConfig, nil
134+
}
135+
66136
func (c *tlsConfig) GetCertificateFunc(stopReload <-chan struct{}, log *logrusx.Logger) (func(*tls.ClientHelloInfo) (*tls.Certificate, error), error) {
67137
if c.certPath != "" && c.keyPath != "" { // attempt to load from disk first (enables hot-reloading)
68138
ctx, cancel := context.WithCancel(context.Background())

driver/config/tls_test.go

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package config
2+
3+
import (
4+
"context"
5+
"crypto/tls"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
10+
"github.com/ory/x/configx"
11+
"github.com/ory/x/logrusx"
12+
)
13+
14+
func TestTLSClientConfig_CipherSuite(t *testing.T) {
15+
l := logrusx.New("", "")
16+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.cipher_suites", []string{"TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"}))
17+
18+
tlsClientConfig, err := c.TLSClientConfigDefault()
19+
assert.NoError(t, err)
20+
cipherSuites := tlsClientConfig.CipherSuites
21+
22+
assert.Len(t, cipherSuites, 2)
23+
assert.Equal(t, tls.TLS_AES_128_GCM_SHA256, cipherSuites[0])
24+
assert.Equal(t, tls.TLS_AES_256_GCM_SHA384, cipherSuites[1])
25+
}
26+
27+
func TestTLSClientConfig_InvalidCipherSuite(t *testing.T) {
28+
l := logrusx.New("", "")
29+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.cipher_suites", []string{"TLS_AES_128_GCM_SHA256", "TLS_INVALID_CIPHER_SUITE"}))
30+
31+
_, err := c.TLSClientConfigDefault()
32+
33+
assert.EqualError(t, err, "Unable to setup client TLS configuration: unsupported cipher \"TLS_INVALID_CIPHER_SUITE\"")
34+
}
35+
36+
func TestTLSClientConfig_MinVersion(t *testing.T) {
37+
l := logrusx.New("", "")
38+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.min_version", "tls13"))
39+
40+
tlsClientConfig, err := c.TLSClientConfigDefault()
41+
42+
assert.NoError(t, err)
43+
assert.Equal(t, uint16(tls.VersionTLS13), tlsClientConfig.MinVersion)
44+
}
45+
46+
func TestTLSClientConfig_InvalidMinVersion(t *testing.T) {
47+
l := logrusx.New("", "")
48+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.min_version", "tlsx"))
49+
50+
_, err := c.TLSClientConfigDefault()
51+
52+
assert.EqualError(t, err, "Unable to setup client TLS configuration. Invalid minimum TLS version: tlsx")
53+
}
54+
55+
func TestTLSClientConfig_MaxVersion(t *testing.T) {
56+
l := logrusx.New("", "")
57+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.max_version", "tls10"))
58+
59+
tlsClientConfig, err := c.TLSClientConfigDefault()
60+
61+
assert.NoError(t, err)
62+
assert.Equal(t, uint16(tls.VersionTLS10), tlsClientConfig.MaxVersion)
63+
}
64+
65+
func TestTLSClientConfig_InvalidMaxTlsVersion(t *testing.T) {
66+
l := logrusx.New("", "")
67+
c := MustNew(context.TODO(), l, configx.WithValue("client.default.tls.max_version", "tlsx"))
68+
69+
_, err := c.TLSClientConfigDefault()
70+
71+
assert.EqualError(t, err, "Unable to setup client TLS configuration. Invalid maximum TLS version: tlsx")
72+
}
73+
74+
func TestTLSClientConfig_WithDefaultFallback(t *testing.T) {
75+
l := logrusx.New("", "")
76+
c := MustNew(context.TODO(), l)
77+
ctx := context.Background()
78+
c.MustSet(ctx, "client.default.tls.min_version", "tls11")
79+
c.MustSet(ctx, "client.default.tls.max_version", "tls12")
80+
c.MustSet(ctx, "client.back_channel_logout.tls.max_version", "tls13")
81+
82+
tlsClientConfig, err := c.TLSClientConfigWithDefaultFallback(KeyPrefixClientBackChannelLogout)
83+
84+
assert.NoError(t, err)
85+
assert.Equal(t, uint16(tls.VersionTLS11), tlsClientConfig.MinVersion)
86+
assert.Equal(t, uint16(tls.VersionTLS13), tlsClientConfig.MaxVersion)
87+
}

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ require (
3131
github.com/gorilla/sessions v1.2.1
3232
github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69
3333
github.com/hashicorp/go-retryablehttp v0.7.1
34+
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1
3435
github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65
3536
github.com/jackc/pgx/v4 v4.16.1
3637
github.com/jmoiron/sqlx v1.3.5
@@ -147,6 +148,9 @@ require (
147148
github.com/gorilla/handlers v1.5.1 // indirect
148149
github.com/gorilla/websocket v1.5.0 // indirect
149150
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2 // indirect
151+
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect
152+
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect
153+
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
150154
github.com/hashicorp/hcl v1.0.0 // indirect
151155
github.com/huandu/xstrings v1.3.2 // indirect
152156
github.com/imdario/mergo v0.3.12 // indirect
@@ -206,6 +210,7 @@ require (
206210
github.com/prometheus/common v0.32.1 // indirect
207211
github.com/prometheus/procfs v0.6.0 // indirect
208212
github.com/rogpeppe/go-internal v1.9.0 // indirect
213+
github.com/ryanuber/go-glob v1.0.0 // indirect
209214
github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect
210215
github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect
211216
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect

go.sum

+8
Original file line numberDiff line numberDiff line change
@@ -827,8 +827,15 @@ github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1
827827
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
828828
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
829829
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
830+
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI=
831+
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
832+
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788=
833+
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
834+
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 h1:Yc026VyMyIpq1UWRnakHRG01U8fJm+nEfEmjoAb00n8=
835+
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1/go.mod h1:l8slYwnJA26yBz+ErHpp2IRCLr0vuOMGBORIz4rRiAs=
830836
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
831837
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
838+
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
832839
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
833840
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
834841
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -1377,6 +1384,7 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
13771384
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
13781385
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
13791386
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
1387+
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
13801388
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
13811389
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
13821390
github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=

0 commit comments

Comments
 (0)