Repository navigation
Expand file tree
/
Copy pathmain.go
More file actions
127 lines (104 loc) · 2.79 KB
/
Copy pathmain.go
File metadata and controls
127 lines (104 loc) · 2.79 KB
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
122
123
124
125
126
127
package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"github.com/gorilla/mux"
"github.com/open-policy-agent/opa/rego"
"log"
"net/http"
"strings"
)
var malformedToken = errors.New("unauthorized: malformed token")
var notAllowed = errors.New("unauthorized: denied by policy")
type OpaResponse struct {
Result bool `json:"result"`
}
func loggingMiddleware() mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.URL.Path)
next.ServeHTTP(w, r)
})
}
}
func evaluateOpaViaHttp(user string) bool {
postBody, _ := json.Marshal(map[string]map[string]string{
"input": {
"user": user,
},
})
resp, err := http.Post("http://localhost:8181/v1/data/example/authz/allow", "application/json", bytes.NewBuffer(postBody))
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
var oResp OpaResponse
if err := json.NewDecoder(resp.Body).Decode(&oResp); err != nil {
log.Fatalln(err)
}
return oResp.Result
}
func evaluateOpaViaApi(user string) bool {
// TODO: How would we get this from OPA or another external source?
module := `
package example.authz
import future.keywords.if
default allow := false
allow if {
input.user = "john"
}`
ctx := context.Background()
query, err := rego.New(
rego.Query("data.example.authz.allow"),
rego.Module("example.rego", module),
).PrepareForEval(ctx)
if err != nil {
log.Fatalln(err)
}
input := map[string]interface{}{"user": user}
results, err := query.Eval(ctx, rego.EvalInput(input))
if err != nil {
log.Fatalln(err)
}
return results.Allowed()
}
func opaMiddleware() mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := strings.Split(r.Header.Get("Authorization"), "Bearer ")
if len(authHeader) != 2 || len(authHeader[1]) == 0 {
http.Error(w, malformedToken.Error(), http.StatusUnauthorized)
return
}
//log.Println(authHeader[1])
if evaluateOpaViaApi(authHeader[1]) != true {
log.Println("Denied access to:", authHeader[1])
http.Error(w, notAllowed.Error(), http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
}
func foo(w http.ResponseWriter, r *http.Request) {
log.Println("Executing: foo")
fmt.Fprintln(w, "foo")
}
func bar(w http.ResponseWriter, r *http.Request) {
log.Println("Executing: bar")
fmt.Fprintln(w, "bar")
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/foo", foo).Methods("GET")
router.HandleFunc("/bar", bar).Methods("GET")
router.Use(loggingMiddleware(), opaMiddleware())
log.Println("Ready")
err := http.ListenAndServe(":8080", router)
if err != nil {
log.Fatalln("There's an error with the server, ", err)
}
}