85 lines
2.6 KiB
Go
85 lines
2.6 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
memberconfig "gateway/internal/model/member/config"
|
|
memberdomain "gateway/internal/model/member/domain"
|
|
domrepo "gateway/internal/model/member/domain/repository"
|
|
domusecase "gateway/internal/model/member/domain/usecase"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type stepUpUseCase struct {
|
|
store domrepo.StepUpStore
|
|
config memberconfig.Config
|
|
}
|
|
|
|
// StepUpUseCaseParam wires StepUpUseCase.
|
|
type StepUpUseCaseParam struct {
|
|
Store domrepo.StepUpStore
|
|
Config memberconfig.Config
|
|
}
|
|
|
|
// MustStepUpUseCase constructs StepUpUseCase.
|
|
func MustStepUpUseCase(param StepUpUseCaseParam) domusecase.StepUpUseCase {
|
|
if param.Store == nil {
|
|
panic("member: step-up store is required")
|
|
}
|
|
return &stepUpUseCase{store: param.Store, config: param.Config.Defaults()}
|
|
}
|
|
|
|
func (uc *stepUpUseCase) Issue(ctx context.Context, req *domusecase.IssueStepUpRequest) (*domusecase.StepUpView, error) {
|
|
if req == nil || req.TenantID == "" || req.UID == "" {
|
|
return nil, errb.InputMissingRequired("tenant_id, uid and purpose are required")
|
|
}
|
|
if !req.Purpose.Valid() {
|
|
return nil, errb.InputInvalidFormat("unsupported step-up purpose")
|
|
}
|
|
ttl := req.TTL
|
|
if ttl <= 0 {
|
|
ttl = time.Duration(uc.config.TOTP.StepUpTTLSeconds) * time.Second
|
|
}
|
|
tokenID := uuid.NewString()
|
|
if err := uc.store.Save(ctx, &domrepo.StepUpSession{
|
|
TokenID: tokenID,
|
|
TenantID: req.TenantID,
|
|
UID: req.UID,
|
|
Purpose: req.Purpose.String(),
|
|
}, ttl); err != nil {
|
|
return nil, wrapRepoErr(err, "save step-up session failed")
|
|
}
|
|
return &domusecase.StepUpView{
|
|
StepUpToken: tokenID,
|
|
ExpiresIn: int(ttl.Seconds()),
|
|
}, nil
|
|
}
|
|
|
|
func (uc *stepUpUseCase) Consume(ctx context.Context, req *domusecase.ConsumeStepUpRequest) error {
|
|
if req == nil || req.TokenID == "" || req.TenantID == "" || req.UID == "" {
|
|
return errb.InputMissingRequired("step_up_token, tenant_id and uid are required")
|
|
}
|
|
if !req.Purpose.Valid() {
|
|
return errb.InputInvalidFormat("unsupported step-up purpose")
|
|
}
|
|
session, err := uc.store.Get(ctx, req.TokenID)
|
|
if err != nil {
|
|
if errors.Is(err, memberdomain.ErrStepUpNotFound) {
|
|
return errb.ResNotFound("step-up session", req.TokenID).WithCause(err)
|
|
}
|
|
return wrapRepoErr(err, "read step-up session failed")
|
|
}
|
|
if session.TenantID != req.TenantID || session.UID != req.UID || session.Purpose != req.Purpose.String() {
|
|
return errb.AuthForbidden("step-up token mismatch")
|
|
}
|
|
if err := uc.store.Delete(ctx, req.TokenID); err != nil {
|
|
return wrapRepoErr(err, "delete step-up session failed")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var _ domusecase.StepUpUseCase = (*stepUpUseCase)(nil)
|