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]