nagisa-kunhah commented on code in PR #1542:
URL: https://github.com/apache/dubbo-admin/pull/1542#discussion_r3927509819


##########
pkg/console/handler/auth.go:
##########
@@ -18,53 +18,159 @@
 package handler
 
 import (
+       "errors"
        "net/http"
+       "slices"
 
        "github.com/gin-contrib/sessions"
        "github.com/gin-gonic/gin"
 
        "github.com/apache/dubbo-admin/pkg/common/bizerror"
+       configauth "github.com/apache/dubbo-admin/pkg/config/console/auth"
+       consoleauth "github.com/apache/dubbo-admin/pkg/console/auth"
        consolectx "github.com/apache/dubbo-admin/pkg/console/context"
        "github.com/apache/dubbo-admin/pkg/console/model"
 )
 
-func Login(ctx consolectx.Context) gin.HandlerFunc {
-       return func(c *gin.Context) {
-               user := c.PostForm("user")
-               password := c.PostForm("password")
-               // verify username and password
-               authCfg := ctx.Config().Console.Auth
-               if user != authCfg.User || password != authCfg.Password {
-                       authErr := bizerror.New(bizerror.Unauthorized, 
"username or password is not correct!")
-                       c.JSON(http.StatusUnauthorized, 
model.NewBizErrorResp(authErr))
-                       return
-               }
-               session := sessions.Default(c)
-               session.Set("user", user)
-               session.Options(sessions.Options{
-                       MaxAge: authCfg.ExpirationTime,
-                       Path:   "/",
-               })
-               err := session.Save()
-               if err != nil {
-                       sessionErr := bizerror.New(bizerror.SessionError, 
err.Error())
-                       c.JSON(http.StatusOK, model.NewBizErrorResp(sessionErr))
-                       return
-               }
-               c.JSON(http.StatusOK, model.NewSuccessResp(true))
+type AuthHandler struct {
+       config  *configauth.Config
+       service *consoleauth.Service
+}
+
+type providersResponse struct {
+       Methods   []string                     `json:"methods"`
+       Providers []consoleauth.PublicProvider `json:"providers"`
+}
+
+func NewAuthHandler(ctx consolectx.Context) (*AuthHandler, error) {
+       config := ctx.Config().Console.Auth
+       service, err := consoleauth.NewService(ctx.AppContext(), 
config.Providers, nil)
+       if err != nil {
+               return nil, err
        }
+       return newAuthHandler(config, service), nil
+}
+
+func newAuthHandler(config *configauth.Config, service *consoleauth.Service) 
*AuthHandler {
+       return &AuthHandler{config: config, service: service}
 }
 
-func Logout(_ consolectx.Context) gin.HandlerFunc {
-       return func(c *gin.Context) {
-               session := sessions.Default(c)
-               session.Clear()
-               err := session.Save()
-               if err != nil {
-                       sessionErr := bizerror.New(bizerror.SessionError, 
err.Error())
-                       c.JSON(http.StatusOK, model.NewBizErrorResp(sessionErr))
-                       return
-               }
-               c.JSON(http.StatusOK, model.NewSuccessResp(true))
+func (h *AuthHandler) Login(c *gin.Context) {
+       if !slices.Contains(h.config.Methods, configauth.MethodPassword) {
+               c.JSON(http.StatusNotFound, 
model.NewBizErrorResp(bizerror.New(bizerror.NotFoundError, "password login is 
not enabled")))
+               return
+       }
+       user := c.PostForm("user")
+       password := c.PostForm("password")
+       if user != h.config.User || password != h.config.Password {
+               c.JSON(http.StatusUnauthorized, 
model.NewBizErrorResp(bizerror.New(bizerror.Unauthorized, "username or password 
is not correct!")))
+               return
+       }
+       session := sessions.Default(c)
+       if err := consoleauth.PutPrincipal(session, 
consoleauth.LocalPrincipal(user)); err != nil {
+               writeSessionError(c, err)
+               return
+       }
+       if err := session.Save(); err != nil {
+               writeSessionError(c, err)
+               return
+       }
+       c.JSON(http.StatusOK, model.NewSuccessResp(true))
+}
+
+func (h *AuthHandler) Logout(c *gin.Context) {
+       session := sessions.Default(c)
+       session.Clear()
+       session.Options(sessions.Options{
+               Path: "/", MaxAge: -1, Secure: h.config.SessionCookieSecure, 
HttpOnly: true, SameSite: http.SameSiteLaxMode,
+       })
+       if err := session.Save(); err != nil {
+               writeSessionError(c, err)
+               return
+       }
+       c.JSON(http.StatusOK, model.NewSuccessResp(true))
+}
+
+func (h *AuthHandler) Providers(c *gin.Context) {
+       c.JSON(http.StatusOK, model.NewSuccessResp(providersResponse{
+               Methods: append([]string(nil), h.config.Methods...), Providers: 
h.service.PublicProviders(),
+       }))
+}
+
+func (h *AuthHandler) ProviderLogin(c *gin.Context) {
+       transaction, authorizationURL, err := 
h.service.Begin(c.Param("provider"))
+       if err != nil {
+               writeProviderError(c, err)
+               return
+       }
+       session := sessions.Default(c)
+       if err := consoleauth.PutOAuthTransaction(session, transaction); err != 
nil {
+               writeSessionError(c, err)
+               return
+       }
+       if err := session.Save(); err != nil {
+               writeSessionError(c, err)
+               return
        }
+       c.Redirect(http.StatusFound, authorizationURL)
+}
+
+func (h *AuthHandler) ProviderCallback(c *gin.Context) {
+       session := sessions.Default(c)
+       transaction, err := consoleauth.ConsumeOAuthTransaction(session)
+       if err != nil {
+               c.JSON(http.StatusBadRequest, 
model.NewBizErrorResp(bizerror.New(bizerror.InvalidArgument, err.Error())))
+               return
+       }
+       // Persist consumption before contacting the Provider so failures 
cannot be replayed.
+       if err := session.Save(); err != nil {
+               writeSessionError(c, err)
+               return
+       }

Review Comment:
   I kept the cookie-backed transaction design here. Replaying the original 
cookie may reach the token exchange again, but the authorization code is 
single-use and the Provider rejects the second exchange, so it cannot create 
another authenticated session. A server-side transaction cache would also 
introduce shared-state and cleanup requirements for multi-instance deployments. 
I updated the misleading comment and test name so they only claim that the 
updated browser cookie clears the transaction.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to