Skip to content

Commit

Permalink
Merge pull request #56 from slok/slok/update-deps
Browse files Browse the repository at this point in the history
Prepare model and config for more token type validators like OIDC
  • Loading branch information
slok authored Nov 10, 2024
2 parents 7b35639 + 7fe83f9 commit 110a9ff
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 76 deletions.
4 changes: 2 additions & 2 deletions internal/app/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

type TokenGetter interface {
GetToken(ctx context.Context, tokenValue string) (*model.Token, error)
GetStaticTokenValidation(ctx context.Context, tokenValue string) (*model.StaticTokenValidation, error)
}

//go:generate mockery --case underscore --output authmock --outpkg authmock --name TokenGetter
Expand Down Expand Up @@ -68,7 +68,7 @@ func (s Service) Authenticate(ctx context.Context, req AuthenticateRequest) (res
logger := s.logger.WithValues(log.Kv{"url": req.Review.HTTPURL, "method": req.Review.HTTPMethod})

// Get token and its properties.
token, err := s.tokenGetter.GetToken(ctx, req.Review.Token)
token, err := s.tokenGetter.GetStaticTokenValidation(ctx, req.Review.Token)
if err != nil {
if errors.Is(err, internalerrors.ErrNotFound) {
logger.Infof("Unknown token")
Expand Down
32 changes: 19 additions & 13 deletions internal/app/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestServiceAuth(t *testing.T) {

"A token review with fails while getting the token it should fail.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "sometoken").Once().Return(nil, fmt.Errorf("something"))
mtg.On("GetStaticTokenValidation", mock.Anything, "sometoken").Once().Return(nil, fmt.Errorf("something"))
},
req: auth.AuthenticateRequest{Review: model.TokenReview{
Token: "sometoken",
Expand All @@ -45,7 +45,7 @@ func TestServiceAuth(t *testing.T) {

"A token review with a valid token that is missing, should not return as authenticated.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "missing").Once().Return(nil, internalerrors.ErrNotFound)
mtg.On("GetStaticTokenValidation", mock.Anything, "missing").Once().Return(nil, internalerrors.ErrNotFound)
},
req: auth.AuthenticateRequest{Review: model.TokenReview{
Token: "missing",
Expand All @@ -55,9 +55,11 @@ func TestServiceAuth(t *testing.T) {

"A token review that is disabled should be invalid.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "token0").Once().Return(&model.Token{
Value: "token0",
Disable: true,
mtg.On("GetStaticTokenValidation", mock.Anything, "token0").Once().Return(&model.StaticTokenValidation{
Value: "token0",
Common: model.TokenCommon{
Disable: true,
},
}, nil)
},
req: auth.AuthenticateRequest{Review: model.TokenReview{
Expand All @@ -68,7 +70,7 @@ func TestServiceAuth(t *testing.T) {

"A token review that has expired should be invalid.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "token0").Once().Return(&model.Token{
mtg.On("GetStaticTokenValidation", mock.Anything, "token0").Once().Return(&model.StaticTokenValidation{
Value: "token0",
ExpiresAt: time.Now().Add(-24 * time.Hour),
}, nil)
Expand All @@ -81,9 +83,11 @@ func TestServiceAuth(t *testing.T) {

"A token review with an invalid URL should be invalid.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "token0").Once().Return(&model.Token{
Value: "token0",
AllowedURL: regexp.MustCompile("https://something.com/.*"),
mtg.On("GetStaticTokenValidation", mock.Anything, "token0").Once().Return(&model.StaticTokenValidation{
Value: "token0",
Common: model.TokenCommon{
AllowedURL: regexp.MustCompile("https://something.com/.*"),
},
}, nil)
},
req: auth.AuthenticateRequest{Review: model.TokenReview{
Expand All @@ -95,9 +99,11 @@ func TestServiceAuth(t *testing.T) {

"A token review with an invalid method should be invalid.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "token0").Once().Return(&model.Token{
Value: "token0",
AllowedMethod: regexp.MustCompile("POST"),
mtg.On("GetStaticTokenValidation", mock.Anything, "token0").Once().Return(&model.StaticTokenValidation{
Value: "token0",
Common: model.TokenCommon{
AllowedMethod: regexp.MustCompile("POST"),
},
}, nil)
},
req: auth.AuthenticateRequest{Review: model.TokenReview{
Expand All @@ -109,7 +115,7 @@ func TestServiceAuth(t *testing.T) {

"A token review that is valid, should be authenticated.": {
mock: func(mtg *authmock.TokenGetter) {
mtg.On("GetToken", mock.Anything, "token0").Once().Return(&model.Token{
mtg.On("GetStaticTokenValidation", mock.Anything, "token0").Once().Return(&model.StaticTokenValidation{
Value: "token0",
ClientID: "client0",
}, nil)
Expand Down
14 changes: 7 additions & 7 deletions internal/app/auth/authmock/token_getter.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions internal/app/auth/token_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ type reviewResult struct {

// Authenticater knows how to authenticate.
type authenticater interface {
Authenticate(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error)
Authenticate(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error)
}

type authenticaterFunc func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error)
type authenticaterFunc func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error)

func (a authenticaterFunc) Authenticate(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
func (a authenticaterFunc) Authenticate(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
return a(ctx, r, t)
}

func newAuthenticaterChain(auths ...authenticater) authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
var res *reviewResult
var err error
for _, a := range auths {
Expand All @@ -52,7 +52,7 @@ func newAuthenticaterChain(auths ...authenticater) authenticater {
}

func newTokenExistAuthenticator() authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
if r.Token == t.Value {
return &reviewResult{Valid: true}, nil
}
Expand All @@ -62,7 +62,7 @@ func newTokenExistAuthenticator() authenticater {
}

func newNotExpiredAuthenticator() authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
if t.ExpiresAt.IsZero() {
return &reviewResult{Valid: true}, nil
}
Expand All @@ -76,12 +76,12 @@ func newNotExpiredAuthenticator() authenticater {
}

func newValidMethodAuthenticator() authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
if t.AllowedMethod == nil {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
if t.Common.AllowedMethod == nil {
return &reviewResult{Valid: true}, nil
}

if t.AllowedMethod.MatchString(r.HTTPMethod) {
if t.Common.AllowedMethod.MatchString(r.HTTPMethod) {
return &reviewResult{Valid: true}, nil
}

Expand All @@ -90,12 +90,12 @@ func newValidMethodAuthenticator() authenticater {
}

func newValidURLAuthenticator() authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
if t.AllowedURL == nil {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
if t.Common.AllowedURL == nil {
return &reviewResult{Valid: true}, nil
}

if t.AllowedURL.MatchString(r.HTTPURL) {
if t.Common.AllowedURL.MatchString(r.HTTPURL) {
return &reviewResult{Valid: true}, nil
}

Expand All @@ -104,8 +104,8 @@ func newValidURLAuthenticator() authenticater {
}

func newDisabledAuthenticator() authenticater {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.Token) (*reviewResult, error) {
if !t.Disable {
return authenticaterFunc(func(ctx context.Context, r model.TokenReview, t model.StaticTokenValidation) (*reviewResult, error) {
if !t.Common.Disable {
return &reviewResult{Valid: true}, nil
}

Expand Down
14 changes: 9 additions & 5 deletions internal/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import (
"time"
)

// Token represents an auth token that can be used to validate an authentication.
// StaticTokenValidation represents an auth static token information that can be used to validate an authentication.
// Token value generation example: `openssl rand -base64 32`.
type Token struct {
Value string
ClientID string
type StaticTokenValidation struct {
Value string
ClientID string
ExpiresAt time.Time
Common TokenCommon
}

type TokenCommon struct {
Disable bool
ExpiresAt time.Time
AllowedURL *regexp.Regexp
AllowedMethod *regexp.Regexp
}
Expand Down
14 changes: 8 additions & 6 deletions internal/storage/memory/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
apiv1 "github.com/slok/simple-ingress-external-auth/pkg/api/v1"
)

func mapJSONV1ToModel(data string) (map[string]model.Token, error) {
func mapJSONV1ToModel(data string) (map[string]model.StaticTokenValidation, error) {
// Substitute env vars in the required strings.
envedData, err := envsubst.EvalEnv(data)
if err != nil {
Expand All @@ -35,7 +35,7 @@ func mapJSONV1ToModel(data string) (map[string]model.Token, error) {
}

// Map.
tokens := map[string]model.Token{}
tokens := map[string]model.StaticTokenValidation{}
for _, t := range c1.Tokens {
if t.Value == "" {
return nil, fmt.Errorf("token value can't be empty")
Expand All @@ -46,27 +46,29 @@ func mapJSONV1ToModel(data string) (map[string]model.Token, error) {
expiresAt = *t.ExpiresAt
}

token := model.Token{
token := model.StaticTokenValidation{
Value: t.Value,
ClientID: t.ClientID,
Disable: t.Disable,
ExpiresAt: expiresAt,
Common: model.TokenCommon{
Disable: t.Disable,
},
}

if t.AllowedMethodRegex != "" {
r, err := regexp.Compile(t.AllowedMethodRegex)
if err != nil {
return nil, fmt.Errorf("could not compile %s regex: %w", t.AllowedMethodRegex, err)
}
token.AllowedMethod = r
token.Common.AllowedMethod = r
}

if t.AllowedURLRegex != "" {
r, err := regexp.Compile(t.AllowedURLRegex)
if err != nil {
return nil, fmt.Errorf("could not compile %s regex: %w", t.AllowedURLRegex, err)
}
token.AllowedURL = r
token.Common.AllowedURL = r
}

// Check same token is not twice.
Expand Down
6 changes: 3 additions & 3 deletions internal/storage/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

type TokenRepository struct {
tokens map[string]model.Token
tokens map[string]model.StaticTokenValidation
}

func NewTokenRepository(logger log.Logger, config string) (*TokenRepository, error) {
Expand All @@ -19,12 +19,12 @@ func NewTokenRepository(logger log.Logger, config string) (*TokenRepository, err
return nil, err
}

logger.WithValues(log.Kv{"svc": "memory.TokenRepository", "tokens": len(tokens)}).Infof("Tokens loaded")
logger.WithValues(log.Kv{"svc": "memory.TokenRepository", "tokens": len(tokens)}).Infof("Token validations loaded")

return &TokenRepository{tokens: tokens}, nil
}

func (t TokenRepository) GetToken(ctx context.Context, tokenValue string) (*model.Token, error) {
func (t TokenRepository) GetStaticTokenValidation(ctx context.Context, tokenValue string) (*model.StaticTokenValidation, error) {
token, ok := t.tokens[tokenValue]
if !ok {
return nil, fmt.Errorf("token not found: %w", internalerrors.ErrNotFound)
Expand Down
Loading

0 comments on commit 110a9ff

Please sign in to comment.