* oidc: add regression tests for token claim json this helps to verify that the same JSON is produced, after these types are refactored. * refactor: use struct types for claim related types BREAKING CHANGE: The following types are changed from interface to struct type: - AccessTokenClaims - IDTokenClaims - IntrospectionResponse - UserInfo and related types. The following methods of OPStorage now take a pointer to a struct type, instead of an interface: - SetUserinfoFromScopes - SetUserinfoFromToken - SetIntrospectionFromToken The following functions are now generic, so that type-safe extension of Claims is now possible: - op.VerifyIDTokenHint - op.VerifyAccessToken - rp.VerifyTokens - rp.VerifyIDToken - Changed UserInfoAddress to pointer in UserInfo and IntrospectionResponse. This was needed to make omitempty work correctly. - Copy or merge maps in IntrospectionResponse and SetUserInfo * op: add example for VerifyAccessToken * fix: rp: wrong assignment in WithIssuedAtMaxAge WithIssuedAtMaxAge assigned its value to v.maxAge, which was wrong. This change fixes that by assiging the duration to v.maxAgeIAT. * rp: add VerifyTokens example * oidc: add standard references to: - IDTokenClaims - IntrospectionResponse - UserInfo * only count coverage for `./pkg/...`
49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package oidc
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// mergeAndMarshalClaims merges registered and the custom
|
|
// claims map into a single JSON object.
|
|
// Registered fields overwrite custom claims.
|
|
func mergeAndMarshalClaims(registered any, claims map[string]any) ([]byte, error) {
|
|
// Use a buffer for memory re-use, instead off letting
|
|
// json allocate a new []byte for every step.
|
|
buf := new(bytes.Buffer)
|
|
|
|
// Marshal the registered claims into JSON
|
|
if err := json.NewEncoder(buf).Encode(registered); err != nil {
|
|
return nil, fmt.Errorf("oidc registered claims: %w", err)
|
|
}
|
|
|
|
if len(claims) > 0 {
|
|
// Merge JSON data into custom claims.
|
|
// The full-read action by the decoder resets the buffer
|
|
// to zero len, while retaining underlaying cap.
|
|
if err := json.NewDecoder(buf).Decode(&claims); err != nil {
|
|
return nil, fmt.Errorf("oidc registered claims: %w", err)
|
|
}
|
|
|
|
// Marshal the final result.
|
|
if err := json.NewEncoder(buf).Encode(claims); err != nil {
|
|
return nil, fmt.Errorf("oidc custom claims: %w", err)
|
|
}
|
|
}
|
|
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// unmarshalJSONMulti unmarshals the same JSON data into multiple destinations.
|
|
// Each destination must be a pointer, as per json.Unmarshal rules.
|
|
// Returns on the first error and destinations may be partly filled with data.
|
|
func unmarshalJSONMulti(data []byte, destinations ...any) error {
|
|
for _, dst := range destinations {
|
|
if err := json.Unmarshal(data, dst); err != nil {
|
|
return fmt.Errorf("oidc: %w into %T", err, dst)
|
|
}
|
|
}
|
|
return nil
|
|
}
|