/
opa-server.go
121 lines (107 loc) · 2.97 KB
/
opa-server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package authorization
import (
"bytes"
"encoding/json"
"net/http"
"strings"
"github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/authx/models"
"github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/config"
"github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/server/utils"
"github.com/oxyno-zeta/s3-proxy/pkg/s3-proxy/tracing"
)
type inputOPA struct {
Input *inputDataOPA `json:"input"`
}
type inputDataOPA struct {
User *models.OIDCUser `json:"user"`
Request *requestDataOPA `json:"request"`
Tags map[string]string `json:"tags"`
}
type requestDataOPA struct {
Method string `json:"method"`
Protocol string `json:"protocol"`
Headers map[string]string `json:"headers"`
RemoteAddr string `json:"remoteAddr"`
Scheme string `json:"scheme"`
Host string `json:"host"`
ParsedPath []string `json:"parsed_path"`
Path string `json:"path"`
}
type opaAnswer struct {
Result bool `json:"result"`
}
func isOPAServerAuthorized(req *http.Request, oidcUser *models.OIDCUser, resource *config.Resource) (bool, error) {
// Get trace from request
trace := tracing.GetTraceFromRequest(req)
// Generate child trace
childTrace := trace.GetChildTrace("opa-server.request")
defer childTrace.Finish()
// Add data
childTrace.SetTag("opa.uri", resource.OIDC.AuthorizationOPAServer.URL)
// Transform headers into map
headers := make(map[string]string)
for k, v := range req.Header {
headers[strings.ToLower(k)] = v[0]
}
// Parse path
parsedPath := deleteEmpty(strings.Split(req.RequestURI, "/"))
// Calculate scheme
scheme := "http"
if req.TLS != nil {
scheme = "https"
}
// Generate OPA Server input data
input := &inputOPA{
Input: &inputDataOPA{
User: oidcUser,
Tags: resource.OIDC.AuthorizationOPAServer.Tags,
Request: &requestDataOPA{
Method: req.Method,
Protocol: req.Proto,
Headers: headers,
RemoteAddr: req.RemoteAddr,
Scheme: scheme,
Host: utils.RequestHost(req),
ParsedPath: parsedPath,
Path: req.RequestURI,
},
},
}
// Json encode body
bb, err := json.Marshal(input)
if err != nil {
return false, err
}
// Making request to OPA server
// Change NewRequest to NewRequestWithContext and pass context it
request, err := http.NewRequestWithContext(req.Context(), http.MethodPost, resource.OIDC.AuthorizationOPAServer.URL, bytes.NewBuffer(bb))
if err != nil {
return false, err
}
// Add content type
request.Header.Add("Content-Type", "application/json")
// Making request to OPA server
resp, err := http.DefaultClient.Do(request)
if err != nil {
return false, err
}
// Defer closing body
defer resp.Body.Close()
// Prepare answer
var answer opaAnswer
// Decode answer
err = json.NewDecoder(resp.Body).Decode(&answer)
if err != nil {
return false, err
}
return answer.Result, nil
}
func deleteEmpty(s []string) []string {
var r []string
for _, str := range s {
if str != "" {
r = append(r, str)
}
}
return r
}