From 7f3f67364f1adf3cf6ca1f8753b512d172679977 Mon Sep 17 00:00:00 2001 From: Darko Luketic Date: Wed, 17 Nov 2021 11:32:58 +0100 Subject: [PATCH] added keycloakclaims package for convenience --- keycloakclaims/claims.go | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 keycloakclaims/claims.go diff --git a/keycloakclaims/claims.go b/keycloakclaims/claims.go new file mode 100644 index 0000000..d233f20 --- /dev/null +++ b/keycloakclaims/claims.go @@ -0,0 +1,78 @@ +package keycloakclaims + +import ( + "errors" + "log" + + "git.icod.de/dalu/ginoidc/ginerror" + "github.com/gin-gonic/gin" +) + +// Claims represent the condensed and stripped version of Keycloak's JWT claims payload +type Claims struct { + Sub string `json:"sub,omitempty"` + RealmAccess struct { + Roles []string `json:"roles,omitempty"` + } `json:"realm_access,omitempty"` + PreferredUsername string `json:"preferred_username,omitempty"` +} + +// FromRequest returns a Claims instance or nil if and error occurs. +// In case of an error it sets or appends to the "oidcerrors" context value of *gin.Context +func FromRequest(cx *gin.Context) *Claims { + claimsValue, found := cx.Get("claims") + if !found { + const errText = "claims not present" + errorType := ginerror.Error{ + Description: errText, + Error: errors.New(errText), + } + if e := addOrExtendErrors(cx, "oidcerrors", errorType); e != nil { + log.Println(e.Error()) + } + return nil + } + + claims, ok := claimsValue.(map[string]interface{}) + if !ok { + const errText = "claims are not of type map[string]interface{}" + errorType := ginerror.Error{ + Description: errText, + Error: errors.New(errText), + } + if e := addOrExtendErrors(cx, "oidcerrors", errorType); e != nil { + log.Println(e.Error()) + } + return nil + } + + c := new(Claims) + c.Sub, _ = claims["sub"].(string) + c.PreferredUsername, _ = claims["preferred_username"].(string) + c.RealmAccess, _ = claims["realm_access"].(struct { + Roles []string `json:"roles,omitempty"` + }) + return c +} + +// addOrExtendErrors adds or appends to the options.ErrorContextKeyName values +func addOrExtendErrors(cx *gin.Context, key string, newerror ginerror.Error) error { + errorsValue, errorsFound := cx.Get("oidcerrors") + if !errorsFound { + var errs []ginerror.Error + errs = append(errs, newerror) + // TODO: find a way to get the error context key from options + cx.Set("oidcerrors", errs) + return nil + } else { + errs, ok := errorsValue.([]ginerror.Error) + if !ok { + return errors.New("claims: errorsValue is not of type []ginerror.Error") + } else { + errs = append(errs, newerror) + // TODO: find a way to get the error context key from options + cx.Set("oidcerrors", errs) + return nil + } + } +}