package oauth2 import ( "errors" "fmt" "net/http" "edge-infra.dev/pkg/edge/iam/apperror" iamErrors "edge-infra.dev/pkg/edge/iam/errors" "edge-infra.dev/pkg/edge/iam/log" "edge-infra.dev/pkg/edge/iam/session" "github.com/gin-gonic/gin" "github.com/ory/fosite" ) func (oauth2 *OAuth2) token(ctx *gin.Context) error { log := log.Get(ctx.Request.Context()) newSession := session.NewSession("") requester, err := oauth2.fosite.NewAccessRequest(ctx, ctx.Request, newSession) if err != nil { return oauth2.handleTokenError(ctx, requester, err) } responder, err := oauth2.fosite.NewAccessResponse(ctx, requester) if err != nil { log.Error(err, "failed to create access response") oauth2.fosite.WriteAccessError(ctx.Writer, requester, err) return nil } oauth2.fosite.WriteAccessResponse(ctx.Writer, requester, responder) return nil } func (oauth2 *OAuth2) handleTokenError(ctx *gin.Context, requester fosite.AccessRequester, err error) error { log := log.Get(ctx.Request.Context()) rfcErr, ok := err.(*fosite.RFC6749Error) if ok { if unWrapErr := rfcErr.Unwrap(); requiresLoginChallenge(unWrapErr) { resultantSession, ok := requester.GetSession().(*session.DefaultSession) if !ok { return apperror.NewStatusError( fmt.Errorf("request requires login. missing or invalid request session: %w", err), http.StatusInternalServerError) } ctx.Header("WWW-Authenticate", fmt.Sprintf(`Login %s`, resultantSession.GetChallenge())) return apperror.NewStatusError( fmt.Errorf("request requires login. returning a login challenge: %w", unWrapErr), http.StatusUnauthorized) } log.Error(err, fmt.Sprintf("failed to create access request, %v", rfcErr.Unwrap().Error())) } else { log.Error(err, "failed to create access request") } oauth2.fosite.WriteAccessError(ctx.Writer, requester, err) return nil } func requiresLoginChallenge(err error) bool { expectedErrors := []error{iamErrors.ErrLoginRequired, iamErrors.ErrExpiredBarcode, iamErrors.ErrUnrecognisedBarcode, iamErrors.ErrInvalidEBCUsage} for _, expectedErr := range expectedErrors { if errors.Is(err, expectedErr) { return true } } return false }