Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.

Commit a14a94f

Browse files
committed
Added proxy mode to furby
1 parent ff92002 commit a14a94f

File tree

9 files changed

+160
-35
lines changed

9 files changed

+160
-35
lines changed

.github/workflows/default.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ jobs:
2020
steps:
2121
- name: Checkout
2222
uses: actions/checkout@v2
23+
with:
24+
fetch-depth: 0
2325
- name: Setup go env
2426
uses: actions/setup-go@v2.1.4
2527
with:

.goreleaser.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
before:
22
hooks:
33
- go mod tidy
4+
45
builds:
5-
-
6-
main: ./cmd/furby
6+
- main: ./cmd/furby
77
env:
88
- CGO_ENABLED=0
99
goos:
1010
- linux
11+
1112
archives:
1213
- replacements:
1314
linux: Linux
1415
amd64: x86_64
16+
1517
checksum:
1618
name_template: 'checksums.txt'
19+
1720
snapshot:
1821
name_template: "{{ incpatch .Version }}-next"
22+
1923
changelog:
24+
use: git
2025
sort: asc
2126
filters:
2227
exclude:
2328
- '^docs:'
2429
- '^test:'
30+
- '^build(deps):'

cmd/furby/furby.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"log"
55
"net/http"
6+
"net/url"
67

78
"github.com/dpattmann/furby/internal/auth"
89
"github.com/dpattmann/furby/internal/config"
@@ -48,9 +49,17 @@ func main() {
4849
authorizer = auth.NewNoOpAuthorizer()
4950
}
5051

51-
tokenHandler := handler.NewStoreHandler(tokenStore, authorizer)
52-
53-
m.Handle(s.Path, tokenHandler)
52+
if s.Target != "" {
53+
target, err := url.Parse("https://www.google.de")
54+
if err != nil {
55+
log.Fatalf("Can't parse url. Error: %v", err)
56+
}
57+
proxyHandler := handler.NewProxyHandler(target, tokenStore, authorizer)
58+
m.Handle(s.Path, proxyHandler)
59+
} else {
60+
tokenHandler := handler.NewStoreHandler(tokenStore, authorizer)
61+
m.Handle(s.Path, tokenHandler)
62+
}
5463
}
5564

5665
m.Handle("/metrics", promhttp.HandlerFor(metrics.PrometheusRegister, promhttp.HandlerOpts{}))

examples/config.json

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
11
{
2-
"auth" : {
2+
"server": {
3+
"tls": false
4+
},
5+
"stores": [
6+
{
7+
"interval": 5,
8+
"path": "/",
9+
"target": "https://api.gateway",
10+
"credentials": {
11+
"id": "integration-tests",
12+
"scopes": [],
13+
"secret": "secret",
14+
"url": "http://localhost:4444/oauth2/token"
15+
},
16+
"auth": {
317
"type": "noop",
418
"user-agents": []
19+
}
520
},
6-
"credentials" : {
7-
"id": "ClientId",
21+
{
22+
"interval": 5,
23+
"path": "/_cache",
24+
"credentials": {
25+
"id": "integration-tests",
826
"scopes": [],
9-
"secret": "ClientSecret",
10-
"url": "https://oauth.server/oauth2/token"
11-
},
12-
"store": {
13-
"interval": 5
14-
},
15-
"server": {
16-
"cert": "",
17-
"key": "",
18-
"tls": false
27+
"secret": "secret",
28+
"url": "http://localhost:4444/oauth2/token"
29+
},
30+
"auth": {
31+
"type": "noop",
32+
"user-agents": []
33+
}
1934
}
35+
]
2036
}

examples/config.yaml

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
---
2-
3-
auth:
4-
type: "noop"
5-
user-agents: []
6-
7-
credentials:
8-
id: "ClientId"
9-
scopes: []
10-
secret: "ClientSecret"
11-
url: "https://oauth.server/oauth2/token"
12-
13-
store:
14-
interval: 5
2+
stores:
3+
- interval: 1
4+
path: /
5+
target: "https://api.gateway"
6+
auth:
7+
type: "noop"
8+
user-agents: [ ]
9+
credentials:
10+
id: "ClientId"
11+
scopes: [ ]
12+
secret: "ClientSecret"
13+
url: "https://oauth.server/oauth2/token"
14+
- interval: 1
15+
path: /_cache
16+
auth:
17+
type: "noop"
18+
user-agents: [ ]
19+
credentials:
20+
id: "ClientId"
21+
scopes: [ ]
22+
secret: "ClientSecret"
23+
url: "https://oauth.server/oauth2/token"
1524

1625
server:
17-
cert: ""
18-
key: ""
19-
tls: false
26+
tls: false

integration/config.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ stores:
99
- scope1
1010
url: http://localhost:4444/oauth2/token
1111
auth:
12-
type: noop
12+
type: noop
13+
14+
server:
15+
tls: false

internal/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Config struct {
1919
}
2020

2121
type Store struct {
22+
Target string `koanf:"target" validate:"omitempty,url"`
2223
Path string `koanf:"path" validate:"required"`
2324
Interval int `koanf:"interval" validate:"required"`
2425
Auth Auth `koanf:"auth" validate:"required"`

internal/handler/error-messages.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ const (
55
JsonParseError = "Error parsing JSON"
66
TeapotMessage = "I'm a teapot"
77
Unauthorized = "Not authorized"
8+
ProxyError = "Proxy error"
89
)

internal/handler/proxy.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package handler
2+
3+
import (
4+
"net/http"
5+
"net/http/httputil"
6+
"net/url"
7+
8+
"github.com/dpattmann/furby/internal/auth"
9+
"github.com/dpattmann/furby/internal/metrics"
10+
"github.com/dpattmann/furby/internal/store"
11+
12+
"github.com/prometheus/client_golang/prometheus"
13+
)
14+
15+
type ProxyHandler struct {
16+
target *url.URL
17+
store store.Store
18+
auth auth.Authorizer
19+
}
20+
21+
func NewProxyHandler(target *url.URL, store store.Store, auth auth.Authorizer) ProxyHandler {
22+
return ProxyHandler{
23+
target: target,
24+
store: store,
25+
auth: auth,
26+
}
27+
}
28+
29+
func (t ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
30+
metrics.ReceivedRequests.Inc()
31+
32+
timer := prometheus.NewTimer(metrics.RequestTime)
33+
defer timer.ObserveDuration()
34+
35+
if req.Method != http.MethodGet {
36+
http.Error(w, TeapotMessage, http.StatusTeapot)
37+
return
38+
}
39+
40+
if !t.auth.IsAuthorized(req) {
41+
http.Error(w, Unauthorized, http.StatusUnauthorized)
42+
return
43+
}
44+
45+
token, err := t.store.GetToken()
46+
47+
if err != nil {
48+
metrics.Http500Errors.Inc()
49+
http.Error(w, TokenStoreError, http.StatusInternalServerError)
50+
return
51+
}
52+
53+
targetQuery := t.target.RawQuery
54+
55+
proxy := &httputil.ReverseProxy{
56+
Director: func(proxyRequest *http.Request) {
57+
proxyRequest.Header.Add("X-Forwarded-Host", proxyRequest.Host)
58+
proxyRequest.Header.Add("X-Origin-Host", t.target.Host)
59+
proxyRequest.Header.Add("Bearer", token.AccessToken)
60+
61+
proxyRequest.URL.Scheme = t.target.Scheme
62+
proxyRequest.URL.Host = t.target.Host
63+
proxyRequest.Host = t.target.Host
64+
65+
if targetQuery == "" || proxyRequest.URL.RawQuery == "" {
66+
proxyRequest.URL.RawQuery = targetQuery + proxyRequest.URL.RawQuery
67+
} else {
68+
proxyRequest.URL.RawQuery = targetQuery + "&" + proxyRequest.URL.RawQuery
69+
}
70+
71+
},
72+
ErrorHandler: func(rw http.ResponseWriter, r *http.Request, err error) {
73+
http.Error(rw, ProxyError, http.StatusInternalServerError)
74+
},
75+
}
76+
77+
proxy.ServeHTTP(w, req)
78+
79+
return
80+
}

0 commit comments

Comments
 (0)