Skip to content
Snippets Groups Projects
Commit 0c9c52c9 authored by Rohith Jayawardene's avatar Rohith Jayawardene Committed by GitHub
Browse files

CORS Headers (#174)

- adding the --enable-cors-global option to enable for all response
- only returning certain headers on OPTIONS request
parent 6206827d
No related branches found
No related tags found
No related merge requests found
#### **2.0.2**
FEATURES:
* adding the --enable-cors-global to switch on CORs header injects into every response
#### **2.0.1** #### **2.0.1**
BUGS: BUGS:
......
...@@ -441,10 +441,9 @@ You are permitted to add CORS following headers into the /oauth uri namespace ...@@ -441,10 +441,9 @@ You are permitted to add CORS following headers into the /oauth uri namespace
Either from the config file: Either from the config file:
```YAML ```YAML
cors: cors-origins:
origins:
- '*' - '*'
methods: cors-methods:
- GET - GET
- POST - POST
``` ```
......
# is the url for retrieve the openid configuration - normally the <server>/auth/realm/<realm_name> # is the url for retrieve the openid configuration - normally the <server>/auth/realm/<realm_name>
discovery-url: https://keycloak.example.com/auth/realms/commons discovery-url: https://keycloak.example.com/auth/realms/commons
# the client id for the 'client' application # the client id for the 'client' application
...@@ -74,17 +73,17 @@ resources: ...@@ -74,17 +73,17 @@ resources:
- openvpn:vpn-user - openvpn:vpn-user
- openvpn:prod-vpn - openvpn:prod-vpn
# set the cross origin resource sharing headers # indicates you want cors headers injects for ALL responses
cors: enable-cors-global: false
# an array of origins (Access-Control-Allow-Origin) # an array of origins (Access-Control-Allow-Origin)
origins: [] cors-origins: []
# an array of headers to apply (Access-Control-Allow-Headers) # an array of headers to apply (Access-Control-Allow-Headers)
headers: [] cors-headers: []
# an array of expose headers (Access-Control-Expose-Headers) # an array of expose headers (Access-Control-Expose-Headers)
exposed-headers: [] cors-exposed-headers: []
# an array of methods (Access-Control-Allow-Methods) # an array of methods (Access-Control-Allow-Methods)
methods: [] cors-methods: []
# the credentials flag (Access-Control-Allow-Credentials) # the credentials flag (Access-Control-Allow-Credentials)
credentials: true|false cors-credentials: true|false
# the max age (Access-Control-Max-Age) # the max age (Access-Control-Max-Age)
max-age: 1h cors-max-age: 1h
...@@ -131,6 +131,8 @@ type Config struct { ...@@ -131,6 +131,8 @@ type Config struct {
// Headers permits adding customs headers across the board // Headers permits adding customs headers across the board
Headers map[string]string `json:"headers" yaml:"headers" usage:"custom headers to the upstream request, key=value"` Headers map[string]string `json:"headers" yaml:"headers" usage:"custom headers to the upstream request, key=value"`
// EnableCorsGlobal enables the CORs header in all response headers
EnableCorsGlobal bool `json:"enable-cors-global" yaml:"enable-cors-global" usage:"inject the CORs headers into all responses" env:"ENABLE_CORS_GLOBAL"`
// EnableForwarding enables the forwarding proxy // EnableForwarding enables the forwarding proxy
EnableForwarding bool `json:"enable-forwarding" yaml:"enable-forwarding" usage:"enables the forwarding proxy mode, signing outbound request"` EnableForwarding bool `json:"enable-forwarding" yaml:"enable-forwarding" usage:"enables the forwarding proxy mode, signing outbound request"`
// EnableSecurityFilter enabled the security handler // EnableSecurityFilter enabled the security handler
......
...@@ -366,26 +366,24 @@ func (r *oauthProxy) admissionMiddleware() gin.HandlerFunc { ...@@ -366,26 +366,24 @@ func (r *oauthProxy) admissionMiddleware() gin.HandlerFunc {
} }
} }
//
// corsMiddleware injects the CORS headers, if set, for request made to /oauth // corsMiddleware injects the CORS headers, if set, for request made to /oauth
//
func (r *oauthProxy) corsMiddleware(c Cors) gin.HandlerFunc { func (r *oauthProxy) corsMiddleware(c Cors) gin.HandlerFunc {
return func(cx *gin.Context) { return func(cx *gin.Context) {
if len(c.Origins) > 0 { if len(c.Origins) > 0 {
cx.Writer.Header().Set("Access-Control-Allow-Origin", strings.Join(c.Origins, ",")) cx.Writer.Header().Set("Access-Control-Allow-Origin", strings.Join(c.Origins, ","))
} }
if c.Credentials {
cx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
}
if len(c.ExposedHeaders) > 0 {
cx.Writer.Header().Set("Access-Control-Expose-Headers", strings.Join(c.ExposedHeaders, ","))
}
if len(c.Methods) > 0 { if len(c.Methods) > 0 {
cx.Writer.Header().Set("Access-Control-Allow-Methods", strings.Join(c.Methods, ",")) cx.Writer.Header().Set("Access-Control-Allow-Methods", strings.Join(c.Methods, ","))
} }
if len(c.Headers) > 0 { if len(c.Headers) > 0 {
cx.Writer.Header().Set("Access-Control-Allow-Headers", strings.Join(c.Headers, ",")) cx.Writer.Header().Set("Access-Control-Allow-Headers", strings.Join(c.Headers, ","))
} }
if len(c.ExposedHeaders) > 0 {
cx.Writer.Header().Set("Access-Control-Expose-Headers", strings.Join(c.ExposedHeaders, ","))
}
if c.Credentials {
cx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
}
if c.MaxAge > 0 { if c.MaxAge > 0 {
cx.Writer.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", int(c.MaxAge.Seconds()))) cx.Writer.Header().Set("Access-Control-Max-Age", fmt.Sprintf("%d", int(c.MaxAge.Seconds())))
} }
......
...@@ -215,10 +215,14 @@ func TestCrossSiteHandler(t *testing.T) { ...@@ -215,10 +215,14 @@ func TestCrossSiteHandler(t *testing.T) {
p, _, _ := newTestProxyService(nil) p, _, _ := newTestProxyService(nil)
cases := []struct { cases := []struct {
Method string
URI string
Cors Cors Cors Cors
Headers map[string]string Headers map[string]string
}{ }{
{ {
Method: http.MethodGet,
URI: "/oauth/test",
Cors: Cors{ Cors: Cors{
Origins: []string{"*"}, Origins: []string{"*"},
}, },
...@@ -227,13 +231,25 @@ func TestCrossSiteHandler(t *testing.T) { ...@@ -227,13 +231,25 @@ func TestCrossSiteHandler(t *testing.T) {
}, },
}, },
{ {
Method: http.MethodGet,
URI: "/oauth/test",
Cors: Cors{ Cors: Cors{
Origins: []string{"*", "https://examples.com"}, Origins: []string{"*", "https://examples.com"},
Methods: []string{"GET"},
}, },
Headers: map[string]string{ Headers: map[string]string{
"Access-Control-Allow-Origin": "*,https://examples.com", "Access-Control-Allow-Origin": "*,https://examples.com",
"Access-Control-Allow-Methods": "GET", },
},
{
Method: http.MethodGet,
URI: "/foo",
Cors: Cors{
Origins: []string{"*", "https://examples.com"},
Methods: []string{"GET", "POST"},
},
Headers: map[string]string{
"Access-Control-Allow-Origin": "*,https://examples.com",
"Access-Control-Allow-Methods": "GET,POST",
}, },
}, },
} }
...@@ -241,7 +257,7 @@ func TestCrossSiteHandler(t *testing.T) { ...@@ -241,7 +257,7 @@ func TestCrossSiteHandler(t *testing.T) {
for i, c := range cases { for i, c := range cases {
handler := p.corsMiddleware(c.Cors) handler := p.corsMiddleware(c.Cors)
// call the handler and check the responses // call the handler and check the responses
context := newFakeGinContext("GET", "/oauth/test") context := newFakeGinContext(c.Method, c.URI)
handler(context) handler(context)
// step: check the headers // step: check the headers
for k, v := range c.Headers { for k, v := range c.Headers {
......
...@@ -166,16 +166,24 @@ func (r *oauthProxy) createReverseProxy() error { ...@@ -166,16 +166,24 @@ func (r *oauthProxy) createReverseProxy() error {
if r.config.EnableSecurityFilter { if r.config.EnableSecurityFilter {
engine.Use(r.securityMiddleware()) engine.Use(r.securityMiddleware())
} }
cors := Cors{
// step: add the routing and cors middleware
oauth := engine.Group(oauthURL).Use(r.corsMiddleware(Cors{
Origins: r.config.CorsOrigins, Origins: r.config.CorsOrigins,
Methods: r.config.CorsMethods, Methods: r.config.CorsMethods,
Headers: r.config.CorsHeaders, Headers: r.config.CorsHeaders,
ExposedHeaders: r.config.CorsExposedHeaders, ExposedHeaders: r.config.CorsExposedHeaders,
Credentials: r.config.CorsCredentials, Credentials: r.config.CorsCredentials,
MaxAge: r.config.CorsMaxAge, MaxAge: r.config.CorsMaxAge,
})) }
// step: enabling globaling?
if r.config.EnableCorsGlobal {
log.Info("enabling CORs header injection globally")
engine.Use(r.corsMiddleware(cors))
}
// step: add the routing and cors middleware
oauth := engine.Group(oauthURL)
if !r.config.EnableCorsGlobal {
oauth.Use(r.corsMiddleware(cors))
}
oauth.GET(authorizationURL, r.oauthAuthorizationHandler) oauth.GET(authorizationURL, r.oauthAuthorizationHandler)
oauth.GET(callbackURL, r.oauthCallbackHandler) oauth.GET(callbackURL, r.oauthCallbackHandler)
oauth.GET(healthURL, r.healthHandler) oauth.GET(healthURL, r.healthHandler)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment