🚚 Moved GrantType into separated grant package
This commit is contained in:
parent
62bc20e243
commit
70d6163099
|
@ -0,0 +1,96 @@
|
|||
package grant
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"source.toby3d.me/toby3d/auth/internal/common"
|
||||
)
|
||||
|
||||
// Type represent fixed grant_type parameter.
|
||||
//
|
||||
// NOTE(toby3d): Encapsulate enums in structs for extra compile-time safety:
|
||||
// https://threedots.tech/post/safer-enums-in-go/#struct-based-enums
|
||||
type Type struct {
|
||||
grantType string
|
||||
}
|
||||
|
||||
//nolint:gochecknoglobals // structs cannot be constants
|
||||
var (
|
||||
Und = Type{} // "und"
|
||||
AuthorizationCode = Type{"authorization_code"} // "authorization_code"
|
||||
RefreshToken = Type{"refresh_token"} // "refresh_token"
|
||||
|
||||
// TicketAuth extension.
|
||||
Ticket = Type{"ticket"}
|
||||
)
|
||||
|
||||
var ErrTypeUnknown error = errors.New("unknown grant type")
|
||||
|
||||
//nolint:gochecknoglobals // maps cannot be constants
|
||||
var uidsTypes = map[string]Type{
|
||||
AuthorizationCode.grantType: AuthorizationCode,
|
||||
RefreshToken.grantType: RefreshToken,
|
||||
Ticket.grantType: Ticket,
|
||||
}
|
||||
|
||||
// ParseType parse grant_type value as Type struct enum.
|
||||
func ParseType(uid string) (Type, error) {
|
||||
if out, ok := uidsTypes[uid]; ok {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
return Und, fmt.Errorf("%w: %s", ErrTypeUnknown, uid)
|
||||
}
|
||||
|
||||
// UnmarshalForm implements custom unmarshler for form values.
|
||||
func (t *Type) UnmarshalForm(v []byte) error {
|
||||
parsed, err := ParseType(strings.ToLower(string(v)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Type: UnmarshalForm: cannot parse value '%s': %w", string(v), err)
|
||||
}
|
||||
|
||||
*t = parsed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom unmarshler for JSON.
|
||||
func (t *Type) UnmarshalJSON(v []byte) error {
|
||||
unquoted, err := strconv.Unquote(string(v))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Type: UnmarshalJSON: cannot unquote value '%s': %w", string(v), err)
|
||||
}
|
||||
|
||||
parsed, err := ParseType(strings.ToLower(unquoted))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Type: UnmarshalJSON: cannot parse value '%s': %w", unquoted, err)
|
||||
}
|
||||
|
||||
*t = parsed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t Type) MarshalJSON() ([]byte, error) {
|
||||
if t == Und {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return []byte(strconv.Quote(t.grantType)), nil
|
||||
}
|
||||
|
||||
// String returns string representation of grant type.
|
||||
func (t Type) String() string {
|
||||
if t == Und {
|
||||
return common.Und
|
||||
}
|
||||
|
||||
return t.grantType
|
||||
}
|
||||
|
||||
func (t Type) GoString() string {
|
||||
return "grant.Type(" + t.String() + ")"
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package grant_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"source.toby3d.me/toby3d/auth/internal/domain/grant"
|
||||
)
|
||||
|
||||
func TestParseType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input string
|
||||
expect grant.Type
|
||||
}{
|
||||
"authorization_code": {input: "authorization_code", expect: grant.AuthorizationCode},
|
||||
"ticket": {input: "ticket", expect: grant.Ticket},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
actual, err := grant.ParseType(tc.input)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if actual != tc.expect {
|
||||
t.Errorf("ParseType(%s) = %v, want %v", tc.input, actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestType_UnmarshalForm(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := []byte("authorization_code")
|
||||
actual := grant.Und
|
||||
|
||||
if err := actual.UnmarshalForm(input); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if actual != grant.AuthorizationCode {
|
||||
t.Errorf("UnmarshalForm(%s) = %v, want %v", input, actual, grant.AuthorizationCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestType_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := []byte(`"authorization_code"`)
|
||||
actual := grant.Und
|
||||
|
||||
if err := actual.UnmarshalJSON(input); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if actual != grant.AuthorizationCode {
|
||||
t.Errorf("UnmarshalJSON(%s) = %v, want %v", input, actual, grant.AuthorizationCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestType_String(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input grant.Type
|
||||
expect string
|
||||
}{
|
||||
"authorization_code": {input: grant.AuthorizationCode, expect: "authorization_code"},
|
||||
"ticket": {input: grant.Ticket, expect: "ticket"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := tc.input.String(); actual != tc.expect {
|
||||
t.Errorf("String() = %v, want %v", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"source.toby3d.me/toby3d/auth/internal/common"
|
||||
)
|
||||
|
||||
// GrantType represent fixed grant_type parameter.
|
||||
//
|
||||
// NOTE(toby3d): Encapsulate enums in structs for extra compile-time safety:
|
||||
// https://threedots.tech/post/safer-enums-in-go/#struct-based-enums
|
||||
type GrantType struct {
|
||||
grantType string
|
||||
}
|
||||
|
||||
//nolint:gochecknoglobals // structs cannot be constants
|
||||
var (
|
||||
GrantTypeUnd = GrantType{grantType: ""} // "und"
|
||||
GrantTypeAuthorizationCode = GrantType{grantType: "authorization_code"} // "authorization_code"
|
||||
GrantTypeRefreshToken = GrantType{grantType: "refresh_token"} // "refresh_token"
|
||||
|
||||
// TicketAuth extension.
|
||||
GrantTypeTicket = GrantType{grantType: "ticket"}
|
||||
)
|
||||
|
||||
var ErrGrantTypeUnknown error = NewError(
|
||||
ErrorCodeInvalidGrant,
|
||||
"unknown grant type",
|
||||
"",
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals // maps cannot be constants
|
||||
var uidsGrantTypes = map[string]GrantType{
|
||||
GrantTypeAuthorizationCode.grantType: GrantTypeAuthorizationCode,
|
||||
GrantTypeRefreshToken.grantType: GrantTypeRefreshToken,
|
||||
GrantTypeTicket.grantType: GrantTypeTicket,
|
||||
}
|
||||
|
||||
// ParseGrantType parse grant_type value as GrantType struct enum.
|
||||
func ParseGrantType(uid string) (GrantType, error) {
|
||||
if grantType, ok := uidsGrantTypes[uid]; ok {
|
||||
return grantType, nil
|
||||
}
|
||||
|
||||
return GrantTypeUnd, fmt.Errorf("%w: %s", ErrGrantTypeUnknown, uid)
|
||||
}
|
||||
|
||||
// UnmarshalForm implements custom unmarshler for form values.
|
||||
func (gt *GrantType) UnmarshalForm(src []byte) error {
|
||||
responseType, err := ParseGrantType(strings.ToLower(string(src)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("GrantType: UnmarshalForm: %w", err)
|
||||
}
|
||||
|
||||
*gt = responseType
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom unmarshler for JSON.
|
||||
func (gt *GrantType) UnmarshalJSON(v []byte) error {
|
||||
unquoted, err := strconv.Unquote(string(v))
|
||||
if err != nil {
|
||||
return fmt.Errorf("GrantType: UnmarshalJSON: cannot unquote value '%s': %w", string(v), err)
|
||||
}
|
||||
|
||||
parsed, err := ParseGrantType(strings.ToLower(unquoted))
|
||||
if err != nil {
|
||||
return fmt.Errorf("GrantType: UnmarshalJSON: cannot parse value '%s': %w", unquoted, err)
|
||||
}
|
||||
|
||||
*gt = parsed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gt GrantType) MarshalJSON() ([]byte, error) {
|
||||
return []byte(strconv.Quote(gt.grantType)), nil
|
||||
}
|
||||
|
||||
// String returns string representation of grant type.
|
||||
func (gt GrantType) String() string {
|
||||
if gt.grantType != "" {
|
||||
return gt.grantType
|
||||
}
|
||||
|
||||
return common.Und
|
||||
}
|
||||
|
||||
func (gt GrantType) GoString() string {
|
||||
return "domain.GrantType(" + gt.String() + ")"
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
//nolint:dupl
|
||||
package domain_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"source.toby3d.me/toby3d/auth/internal/domain"
|
||||
)
|
||||
|
||||
func TestParseGrantType(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
in string
|
||||
out domain.GrantType
|
||||
}{
|
||||
{in: "authorization_code", out: domain.GrantTypeAuthorizationCode},
|
||||
{in: "ticket", out: domain.GrantTypeTicket},
|
||||
} {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.in, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result, err := domain.ParseGrantType(tc.in)
|
||||
if err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if result != tc.out {
|
||||
t.Errorf("ParseGrantType(%s) = %v, want %v", tc.in, result, tc.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantType_UnmarshalForm(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := []byte("authorization_code")
|
||||
result := domain.GrantTypeUnd
|
||||
|
||||
if err := result.UnmarshalForm(input); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if result != domain.GrantTypeAuthorizationCode {
|
||||
t.Errorf("UnmarshalForm(%s) = %v, want %v", input, result, domain.GrantTypeAuthorizationCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantType_UnmarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
input := []byte(`"authorization_code"`)
|
||||
result := domain.GrantTypeUnd
|
||||
|
||||
if err := result.UnmarshalJSON(input); err != nil {
|
||||
t.Fatalf("%+v", err)
|
||||
}
|
||||
|
||||
if result != domain.GrantTypeAuthorizationCode {
|
||||
t.Errorf("UnmarshalJSON(%s) = %v, want %v", input, result, domain.GrantTypeAuthorizationCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrantType_String(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
in domain.GrantType
|
||||
out string
|
||||
}{
|
||||
{name: "authorization_code", in: domain.GrantTypeAuthorizationCode, out: "authorization_code"},
|
||||
{name: "ticket", in: domain.GrantTypeTicket, out: "ticket"},
|
||||
} {
|
||||
tc := tc
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := tc.in.String()
|
||||
if result != tc.out {
|
||||
t.Errorf("String() = %v, want %v", result, tc.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package domain
|
|||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"source.toby3d.me/toby3d/auth/internal/domain/grant"
|
||||
)
|
||||
|
||||
type Metadata struct {
|
||||
|
@ -57,7 +59,7 @@ type Metadata struct {
|
|||
|
||||
// JSON array containing grant type values supported. If omitted, the
|
||||
// default value differs from RFC8414 and is authorization_code.
|
||||
GrantTypesSupported []GrantType
|
||||
GrantTypesSupported []grant.Type
|
||||
|
||||
// JSON array containing the methods supported for PKCE. This parameter
|
||||
// differs from RFC8414 in that it is not optional as PKCE is REQUIRED.
|
||||
|
@ -112,9 +114,9 @@ func TestMetadata(tb testing.TB) *Metadata {
|
|||
ResponseTypeCode,
|
||||
ResponseTypeID,
|
||||
},
|
||||
GrantTypesSupported: []GrantType{
|
||||
GrantTypeAuthorizationCode,
|
||||
GrantTypeTicket,
|
||||
GrantTypesSupported: []grant.Type{
|
||||
grant.AuthorizationCode,
|
||||
grant.Ticket,
|
||||
},
|
||||
CodeChallengeMethodsSupported: []CodeChallengeMethod{
|
||||
CodeChallengeMethodMD5,
|
||||
|
|
Loading…
Reference in New Issue