2021-11-17 11:32:58 +01:00
|
|
|
package keycloakclaims
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"log"
|
|
|
|
|
2022-10-18 12:04:48 +02:00
|
|
|
"code.icod.de/dalu/ginoidc/ginerror"
|
2021-11-17 11:32:58 +01:00
|
|
|
"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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|