package main
import (
"context"
"encoding/json"
"fmt"
"github.com/open-policy-agent/opa/rego"
"io/ioutil"
"net/http"
"net/url"
"os"
)
type Jwttoken struct {
Access_token string
Expires_in int
Refresh_expires_in int
Refresh_token string
Token_type string
Not_before_policy int
Session_state string
Scope string
}
var token Jwttoken
var opaPolicy string = `
package authz
import future.keywords.in
default allow = false
jwks := jwks_request("http://keycloak:8080/auth/realms/opa/protocol/openid-connect/certs").body
filtered_jwks := [ key |
some key in jwks.keys
key.use == "sig"
]
token_cert := json.marshal({"keys": filtered_jwks})
token = { "isValid": isValid, "header": header, "payload": payload } {
[isValid, header, payload] := io.jwt.decode_verify(input, { "cert": token_cert, "aud": "account", "iss": "http://keycloak:808
0/auth/realms/opa"})
}
allow {
is_token_valid
}
is_token_valid {
token.isValid
now := time.now_ns() / 1000000000
token.payload.iat <= now
now < token.payload.exp
token.payload.clientRole == "[opa-client-role]"
}
jwks_request(url) = http.send({
"url": url,
"method": "GET",
"force_cache": true,
"force_json_decode": true,
"force_cache_duration_seconds": 3600 # Cache response for an hour
})
`
func getToken() string {
clientSecret := "63wkv0RUXkp01pbqtNTSwghhTxeMW55I"
clientId := "opacli"
realmName := "opa"
keycloakHost := "keycloak"
keycloakPort := "8080"
keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName + "/protocol/openid-connect/token" resp, err := http.PostForm(keycloakUrl,
url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
if err != nil {
fmt.Println(err)
panic("Something wrong with the credentials or url ")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
json.Unmarshal([]byte(body), &token)
return token.Access_token
}
func traceOpa(input string) {
ctx := context.TODO()
test := rego.New(
rego.Query("x = data.authz.allow"),
rego.Trace(true),
rego.Module("example.rego", opaPolicy),
rego.Input(input),
)
test.Eval(ctx)
rego.PrintTraceWithLocation(os.Stdout, test)
}
func evaluateOpa(input string) {
ctx := context.TODO()
query, err := rego.New(
rego.Query("x = data.authz.allow"),
rego.Module("example.rego", opaPolicy),
).PrepareForEval(ctx)
if err != nil {
// Handle error.
fmt.Println(err.Error())
}
results, err := query.Eval(ctx, rego.EvalInput(input))
// Inspect results.
if err != nil {
// Handle evaluation error.
fmt.Println("Error: " + err.Error())
} else if len(results) == 0 {
// Handle undefined result.
fmt.Println("Results are empty")
} else {
// Handle result/decision.
fmt.Printf("Results = %+v\n", results) //=> [{Expressions:[true] Bindings:map[x:true]}]
}
}
func main() {
tokenStr := getToken()
traceOpa(tokenStr)
evaluateOpa(tokenStr)
}
|