Skip to content

Commit 3979240

Browse files
authored
Merge pull request #2 from computate/kruizeproject
Add support for exported_namespace GPU metrics filter and better logging to prom-keycloak-proxy
2 parents 28fad56 + d8e7554 commit 3979240

File tree

3 files changed

+99
-23
lines changed

3 files changed

+99
-23
lines changed

queries/parse.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func InjectMatcher(q url.Values, matcher *labels.Matcher) error {
6363
return nil
6464
}
6565

66-
func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key string, defaultValue string) error {
66+
func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key string, authKey string, defaultValue string) (string, string, error) {
6767
value := defaultValue
6868
matchers := queryValues[QueryParam]
6969
for _, matcher := range matchers {
@@ -76,21 +76,32 @@ func AppendMatcher(queryValues url.Values, queryValuesForAuth url.Values, key st
7676
}
7777
}
7878
matcher := &labels.Matcher{
79-
Name: key,
79+
Name: authKey,
8080
Type: labels.MatchRegexp,
8181
Value: LabelValuesToRegexpString([]string{value}),
8282
}
8383
err := InjectMatcher(queryValuesForAuth, matcher)
84-
return err
84+
return authKey, value, err
8585
}
8686

87-
func ParseAuthorizations(queryValues url.Values) url.Values {
87+
func ParseAuthorizations(queryValues url.Values) (url.Values, []string, []string) {
8888
queryValuesForAuth := make(url.Values)
8989

90-
AppendMatcher(queryValues, queryValuesForAuth, "cluster", "all clusters")
91-
AppendMatcher(queryValues, queryValuesForAuth, "namespace", "all namespaces")
90+
var keys []string
91+
var values []string
92+
cluster_key, cluster, _ := AppendMatcher(queryValues, queryValuesForAuth, "cluster", "cluster", "all clusters")
93+
keys = append(keys, cluster_key)
94+
values = append(values, cluster)
9295

93-
return queryValuesForAuth
96+
exported_namespace_key, exported_namespace, _ := AppendMatcher(queryValues, queryValuesForAuth, "exported_namespace", "namespace", "all namespaces")
97+
keys = append(keys, exported_namespace_key)
98+
values = append(values, exported_namespace)
99+
100+
namespace_key, namespace, _ := AppendMatcher(queryValues, queryValuesForAuth, "namespace", "namespace", exported_namespace)
101+
keys = append(keys, namespace_key)
102+
values = append(values, namespace)
103+
104+
return queryValuesForAuth, keys, values
94105
}
95106

96107
func QueryPrometheus(prometheusTlsCertPath string, prometheusTlsKeyPath string,

services/authService.go

Lines changed: 81 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"crypto/tls"
99
"encoding/json"
1010
"net/http"
11+
"slices"
1112
"strings"
1213

1314
"github.com/OCP-on-NERC/prom-keycloak-proxy/errors"
@@ -66,6 +67,27 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
6667
return
6768
}
6869

70+
userInfo, err := gocloakClient.GetUserInfo(context.Background(), accessToken, authRealm)
71+
if err != nil {
72+
log.Warn().
73+
Int("status", 401).
74+
Str("method", r.Method).
75+
Str("path", r.RequestURI).
76+
Str("ip", r.RemoteAddr).
77+
Str("client-id", authClientId).
78+
Str("query", query).
79+
Msg("Unauthorized")
80+
81+
w.WriteHeader(401)
82+
json.NewEncoder(w).Encode(errors.BadRequestError(err.Error()))
83+
return
84+
}
85+
username := *userInfo.PreferredUsername
86+
var userClientId string = ""
87+
if strings.Contains(username, "service-account-") {
88+
userClientId = strings.ReplaceAll(username, "service-account-", "")
89+
}
90+
6991
isTokenValid := *rptResult.Active
7092

7193
if !isTokenValid {
@@ -74,7 +96,8 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
7496
Str("method", r.Method).
7597
Str("path", r.RequestURI).
7698
Str("ip", r.RemoteAddr).
77-
Str("client-id", authClientId).
99+
Str("username", username).
100+
Str("client-id", userClientId).
78101
Str("query", query).
79102
Msg("Unauthorized")
80103

@@ -84,7 +107,7 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
84107
}
85108

86109
queryValues := r.URL.Query()
87-
queryValuesForAuth := queries.ParseAuthorizations(queryValues)
110+
queryValuesForAuth, keys, values := queries.ParseAuthorizations(queryValues)
88111
matchers := queryValuesForAuth[queries.QueryParam]
89112
var permissions []string
90113

@@ -107,15 +130,16 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
107130
},
108131
)
109132

110-
if err != nil || len(*rpp) < 2 {
133+
if err != nil {
111134
log.Warn().
112135
Int("status", 403).
113136
Str("method", r.Method).
114137
Str("path", r.RequestURI).
115138
Str("ip", r.RemoteAddr).
116-
Str("client-id", authClientId).
139+
Str("username", username).
140+
Str("client-id", userClientId).
117141
Str("query", query).
118-
Msg("Forbidden")
142+
Msg(err.Error())
119143

120144
w.WriteHeader(403)
121145
json.NewEncoder(w).Encode(errors.UnauthorizedError())
@@ -129,7 +153,8 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
129153
Str("method", r.Method).
130154
Str("path", r.RequestURI).
131155
Str("ip", r.RemoteAddr).
132-
Str("client-id", authClientId).
156+
Str("username", username).
157+
Str("client-id", userClientId).
133158
Str("query", query).
134159
Msg("Bad Request")
135160

@@ -138,15 +163,56 @@ func Protect(gocloakClient *gocloak.GoCloak, authRealm string, authClientId stri
138163
return
139164
}
140165

141-
log.Info().
142-
Int("status", 200).
143-
Str("method", r.Method).
144-
Str("path", r.RequestURI).
145-
Str("ip", r.RemoteAddr).
146-
Str("client-id", authClientId).
147-
Str("query", query).
148-
RawJSON("permissions", out).
149-
Msg("OK")
166+
var final_result bool = true
167+
var unauthorized_key string = ""
168+
var unauthorized_value string = ""
169+
for i, key := range keys {
170+
value := values[i]
171+
current_result := false
172+
for _, permission := range *rpp {
173+
if key == *permission.ResourceName && slices.Contains(*permission.Scopes, value) {
174+
current_result = true
175+
break
176+
}
177+
}
178+
if !current_result {
179+
final_result = false
180+
unauthorized_key = key
181+
unauthorized_value = value
182+
break
183+
}
184+
}
185+
186+
if final_result {
187+
log.Info().
188+
Int("status", 200).
189+
Str("method", r.Method).
190+
Str("path", r.RequestURI).
191+
Str("ip", r.RemoteAddr).
192+
Str("username", username).
193+
Str("client-id", userClientId).
194+
Str("query", query).
195+
RawJSON("permissions", out).
196+
Msg("OK")
197+
} else {
198+
message := "You are not authorized to access the resource \"" + unauthorized_key + "\" with scope \"" + unauthorized_value + "\""
199+
log.Warn().
200+
Int("status", 403).
201+
Str("method", r.Method).
202+
Str("path", r.RequestURI).
203+
Str("ip", r.RemoteAddr).
204+
Str("username", username).
205+
Str("client-id", userClientId).
206+
Str("query", query).
207+
Msg(message)
208+
209+
w.WriteHeader(403)
210+
json.NewEncoder(w).Encode(errors.HttpError{
211+
Code: 403,
212+
Error: "Forbidden",
213+
Message: message})
214+
return
215+
}
150216

151217
// Our middleware logic goes here...
152218
next.ServeHTTP(w, r)

services/promService.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ func PromQueryHandler(gocloakClient *gocloak.GoCloak, authRealm string, authClie
1919

2020
queryValues := r.URL.Query()
2121
matchers := queryValues[queries.QueryParam]
22-
//v := make(url.Values)
2322
for _, matcher := range matchers {
2423
expr, _ := parser.ParseExpr(matcher)
2524
queryValues.Set(queries.QueryParam, expr.String())

0 commit comments

Comments
 (0)