From ee34b61b0cabf0eac6f7a92e4171e9a29fb7afa2 Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Thu, 11 Nov 2021 14:24:33 +0100 Subject: [PATCH 1/2] Add the reverseproxy http service --- changelog/unreleased/http-reverseproxy.md | 7 ++ internal/http/services/loader/loader.go | 1 + .../services/reverseproxy/reverseproxy.go | 118 ++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 changelog/unreleased/http-reverseproxy.md create mode 100644 internal/http/services/reverseproxy/reverseproxy.go diff --git a/changelog/unreleased/http-reverseproxy.md b/changelog/unreleased/http-reverseproxy.md new file mode 100644 index 0000000000..e9f5501444 --- /dev/null +++ b/changelog/unreleased/http-reverseproxy.md @@ -0,0 +1,7 @@ +Enhancement: Add the reverseproxy http service + +This PR adds an HTTP service which does the job of authenticating incoming +requests via the reva middleware before forwarding them to the respective +backends. This is useful for extensions which do not have the auth mechanisms. + +https://github.com/cs3org/reva/pull/2268 \ No newline at end of file diff --git a/internal/http/services/loader/loader.go b/internal/http/services/loader/loader.go index 07edbc6aec..7548a93f32 100644 --- a/internal/http/services/loader/loader.go +++ b/internal/http/services/loader/loader.go @@ -32,6 +32,7 @@ import ( _ "github.com/cs3org/reva/internal/http/services/owncloud/ocdav" _ "github.com/cs3org/reva/internal/http/services/owncloud/ocs" _ "github.com/cs3org/reva/internal/http/services/prometheus" + _ "github.com/cs3org/reva/internal/http/services/reverseproxy" _ "github.com/cs3org/reva/internal/http/services/siteacc" _ "github.com/cs3org/reva/internal/http/services/sysinfo" _ "github.com/cs3org/reva/internal/http/services/wellknown" diff --git a/internal/http/services/reverseproxy/reverseproxy.go b/internal/http/services/reverseproxy/reverseproxy.go new file mode 100644 index 0000000000..2d0da6c46c --- /dev/null +++ b/internal/http/services/reverseproxy/reverseproxy.go @@ -0,0 +1,118 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package reverseproxy + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httputil" + "net/url" + + ctxpkg "github.com/cs3org/reva/pkg/ctx" + "github.com/cs3org/reva/pkg/rhttp/global" + "github.com/go-chi/chi/v5" + "github.com/mitchellh/mapstructure" + "github.com/rs/zerolog" +) + +func init() { + global.Register("reverseproxy", New) +} + +type proxyRule struct { + Endpoint string `mapstructure:"endpoint" json:"endpoint"` + Backend string `mapstructure:"backend" json:"backend"` +} + +type Config struct { + ProxyRulesJSON string `mapstructure:"proxy_rules_json"` +} + +func (c *Config) init() { + if c.ProxyRulesJSON == "" { + c.ProxyRulesJSON = "/etc/revad/proxy_rules.json" + } +} + +type svc struct { + router *chi.Mux +} + +func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) { + conf := &Config{} + if err := mapstructure.Decode(m, conf); err != nil { + return nil, err + } + conf.init() + + f, err := ioutil.ReadFile(conf.ProxyRulesJSON) + if err != nil { + return nil, err + } + + var rules []proxyRule + err = json.Unmarshal(f, &rules) + if err != nil { + return nil, err + } + + r := chi.NewRouter() + + for _, rule := range rules { + remote, err := url.Parse(rule.Backend) + if err != nil { + // Skip the rule if the backend is not a valid URL + continue + } + + proxy := httputil.NewSingleHostReverseProxy(remote) + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.Host = remote.Host + if token, ok := ctxpkg.ContextGetToken(r.Context()); ok { + r.Header.Set(ctxpkg.TokenHeader, token) + } + proxy.ServeHTTP(w, r) + }) + r.Mount(rule.Endpoint, handler) + } + + return &svc{router: r}, nil +} + +func (s *svc) Close() error { + return nil +} + +func (s *svc) Prefix() string { + // This service will be served at root + return "" +} + +func (s *svc) Unprotected() []string { + // TODO: If the services which will be served via the reverse proxy have unprotected endpoints, + // we won't be able to support those at the moment. + return []string{} +} + +func (s *svc) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + s.router.ServeHTTP(w, r) + }) +} From ff44b875056bd643eb3a24ecb24fc98b78c375e3 Mon Sep 17 00:00:00 2001 From: Ishank Arora Date: Thu, 11 Nov 2021 14:29:02 +0100 Subject: [PATCH 2/2] Add comments --- internal/http/services/reverseproxy/reverseproxy.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/http/services/reverseproxy/reverseproxy.go b/internal/http/services/reverseproxy/reverseproxy.go index 2d0da6c46c..09d7d968a3 100644 --- a/internal/http/services/reverseproxy/reverseproxy.go +++ b/internal/http/services/reverseproxy/reverseproxy.go @@ -41,11 +41,11 @@ type proxyRule struct { Backend string `mapstructure:"backend" json:"backend"` } -type Config struct { +type config struct { ProxyRulesJSON string `mapstructure:"proxy_rules_json"` } -func (c *Config) init() { +func (c *config) init() { if c.ProxyRulesJSON == "" { c.ProxyRulesJSON = "/etc/revad/proxy_rules.json" } @@ -55,8 +55,9 @@ type svc struct { router *chi.Mux } +// New returns an instance of the reverse proxy service func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) { - conf := &Config{} + conf := &config{} if err := mapstructure.Decode(m, conf); err != nil { return nil, err }