mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-11 04:09:05 +02:00
refactor: authorize API routes with per-endpoint scopes (#1823)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
copilot-swe-agent[bot]
parent
1bd6f006c8
commit
0ec6bfa191
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/tracing"
|
||||
)
|
||||
|
||||
@@ -23,8 +23,7 @@ type TestEmailSender interface {
|
||||
// @Description Initialize routes for application configuration
|
||||
// @Tags Application Configuration
|
||||
func NewAppConfigController(
|
||||
group *gin.RouterGroup,
|
||||
authMiddleware *middleware.AuthMiddleware,
|
||||
r *authz.Router,
|
||||
appConfigService *appconfig.AppConfigService,
|
||||
emailSender TestEmailSender,
|
||||
) {
|
||||
@@ -33,11 +32,11 @@ func NewAppConfigController(
|
||||
appConfigService: appConfigService,
|
||||
emailSender: emailSender,
|
||||
}
|
||||
group.GET("/application-configuration", httpserver.Handle(acc.listAppConfigHandler))
|
||||
group.GET("/application-configuration/all", authMiddleware.Add(), httpserver.Handle(acc.listAllAppConfigHandler))
|
||||
group.PUT("/application-configuration", authMiddleware.Add(), httpserver.Handle(acc.updateAppConfigHandler))
|
||||
r.Public().GET("/application-configuration", httpserver.Handle(acc.listAppConfigHandler))
|
||||
r.GET("/application-configuration/all", authz.ConfigRead, httpserver.Handle(acc.listAllAppConfigHandler))
|
||||
r.PUT("/application-configuration", authz.ConfigWrite, httpserver.Handle(acc.updateAppConfigHandler))
|
||||
|
||||
group.POST("/application-configuration/test-email", authMiddleware.Add(), httpserver.Handle(acc.testEmailHandler))
|
||||
r.POST("/application-configuration/test-email", authz.ConfigWrite, httpserver.Handle(acc.testEmailHandler))
|
||||
}
|
||||
|
||||
type AppConfigController struct {
|
||||
@@ -169,7 +168,7 @@ func (acc *AppConfigController) testEmailHandler(c *gin.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
|
||||
err = acc.emailSender.SendTestEmail(c.Request.Context(), dbConfig, userID)
|
||||
if err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
kitutils "github.com/italypaleale/go-kit/utils"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/apperror"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
_ "github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||
@@ -18,8 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func NewAppImagesController(
|
||||
group *gin.RouterGroup,
|
||||
authMiddleware *middleware.AuthMiddleware,
|
||||
r *authz.Router,
|
||||
fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware,
|
||||
appImagesService *service.AppImagesService,
|
||||
) {
|
||||
@@ -27,21 +27,21 @@ func NewAppImagesController(
|
||||
appImagesService: appImagesService,
|
||||
}
|
||||
|
||||
group.GET("/application-images/logo", httpserver.Handle(controller.getLogoHandler))
|
||||
group.GET("/application-images/email", httpserver.Handle(controller.getEmailLogoHandler))
|
||||
group.GET("/application-images/background", httpserver.Handle(controller.getBackgroundImageHandler))
|
||||
group.GET("/application-images/favicon", httpserver.Handle(controller.getFaviconHandler))
|
||||
group.GET("/application-images/default-profile-picture", authMiddleware.Add(), httpserver.Handle(controller.getDefaultProfilePicture))
|
||||
r.Public().GET("/application-images/logo", httpserver.Handle(controller.getLogoHandler))
|
||||
r.Public().GET("/application-images/email", httpserver.Handle(controller.getEmailLogoHandler))
|
||||
r.Public().GET("/application-images/background", httpserver.Handle(controller.getBackgroundImageHandler))
|
||||
r.Public().GET("/application-images/favicon", httpserver.Handle(controller.getFaviconHandler))
|
||||
r.GET("/application-images/default-profile-picture", authz.ConfigRead, httpserver.Handle(controller.getDefaultProfilePicture))
|
||||
|
||||
group.PUT("/application-images/logo", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateLogoHandler))
|
||||
group.PUT("/application-images/email", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateEmailLogoHandler))
|
||||
group.PUT("/application-images/background", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateBackgroundImageHandler))
|
||||
group.PUT("/application-images/favicon", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateFaviconHandler))
|
||||
group.PUT("/application-images/default-profile-picture", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateDefaultProfilePicture))
|
||||
r.PUT("/application-images/logo", authz.ConfigWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateLogoHandler))
|
||||
r.PUT("/application-images/email", authz.ConfigWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateEmailLogoHandler))
|
||||
r.PUT("/application-images/background", authz.ConfigWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateBackgroundImageHandler))
|
||||
r.PUT("/application-images/favicon", authz.ConfigWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateFaviconHandler))
|
||||
r.PUT("/application-images/default-profile-picture", authz.ConfigWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(controller.updateDefaultProfilePicture))
|
||||
|
||||
group.DELETE("/application-images/logo", authMiddleware.Add(), httpserver.Handle(controller.deleteLogoHandler))
|
||||
group.DELETE("/application-images/background", authMiddleware.Add(), httpserver.Handle(controller.deleteBackgroundImageHandler))
|
||||
group.DELETE("/application-images/default-profile-picture", authMiddleware.Add(), httpserver.Handle(controller.deleteDefaultProfilePicture))
|
||||
r.DELETE("/application-images/logo", authz.ConfigWrite, httpserver.Handle(controller.deleteLogoHandler))
|
||||
r.DELETE("/application-images/background", authz.ConfigWrite, httpserver.Handle(controller.deleteBackgroundImageHandler))
|
||||
r.DELETE("/application-images/default-profile-picture", authz.ConfigWrite, httpserver.Handle(controller.deleteDefaultProfilePicture))
|
||||
}
|
||||
|
||||
type AppImagesController struct {
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||
)
|
||||
|
||||
@@ -14,16 +14,13 @@ import (
|
||||
// @Summary Custom claim management controller
|
||||
// @Description Initializes all custom claim-related API endpoints
|
||||
// @Tags Custom Claims
|
||||
func NewCustomClaimController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, customClaimService *service.CustomClaimService) {
|
||||
func NewCustomClaimController(r *authz.Router, customClaimService *service.CustomClaimService) {
|
||||
wkc := &CustomClaimController{customClaimService: customClaimService}
|
||||
|
||||
customClaimsGroup := group.Group("/custom-claims")
|
||||
customClaimsGroup.Use(authMiddleware.Add())
|
||||
{
|
||||
customClaimsGroup.GET("/suggestions", httpserver.Handle(wkc.getSuggestionsHandler))
|
||||
customClaimsGroup.PUT("/user/:userId", httpserver.Handle(wkc.UpdateCustomClaimsForUserHandler))
|
||||
customClaimsGroup.PUT("/user-group/:userGroupId", httpserver.Handle(wkc.UpdateCustomClaimsForUserGroupHandler))
|
||||
}
|
||||
customClaimsGroup := r.Group("/custom-claims")
|
||||
customClaimsGroup.GET("/suggestions", authz.UsersRead, httpserver.Handle(wkc.getSuggestionsHandler))
|
||||
customClaimsGroup.PUT("/user/:userId", authz.UsersWrite, httpserver.Handle(wkc.UpdateCustomClaimsForUserHandler))
|
||||
customClaimsGroup.PUT("/user-group/:userGroupId", authz.GroupsWrite, httpserver.Handle(wkc.UpdateCustomClaimsForUserGroupHandler))
|
||||
}
|
||||
|
||||
type CustomClaimController struct {
|
||||
|
||||
@@ -7,19 +7,20 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||
)
|
||||
|
||||
func NewTestController(group *gin.RouterGroup, testService *service.TestService) {
|
||||
func NewTestController(r *authz.PublicRouter, testService *service.TestService) {
|
||||
testController := &TestController{TestService: testService}
|
||||
|
||||
group.POST("/test/reset", httpserver.Handle(testController.resetAndSeedHandler))
|
||||
group.POST("/test/accesstoken", httpserver.Handle(testController.signAccessToken))
|
||||
group.POST("/test/refreshtoken", httpserver.Handle(testController.signRefreshToken))
|
||||
r.POST("/test/reset", httpserver.Handle(testController.resetAndSeedHandler))
|
||||
r.POST("/test/accesstoken", httpserver.Handle(testController.signAccessToken))
|
||||
r.POST("/test/refreshtoken", httpserver.Handle(testController.signRefreshToken))
|
||||
|
||||
group.GET("/externalidp/jwks.json", httpserver.Handle(testController.externalIdPJWKS))
|
||||
group.POST("/externalidp/sign", httpserver.Handle(testController.externalIdPSignToken))
|
||||
r.GET("/externalidp/jwks.json", httpserver.Handle(testController.externalIdPJWKS))
|
||||
r.POST("/externalidp/sign", httpserver.Handle(testController.externalIdPSignToken))
|
||||
}
|
||||
|
||||
type TestController struct {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/apperror"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||
@@ -21,38 +22,38 @@ import (
|
||||
// @Summary OIDC controller
|
||||
// @Description Initializes all OIDC-related API endpoints for authentication and client management
|
||||
// @Tags OIDC
|
||||
func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, oidcService *service.OidcService, appConfigService appconfig.AppConfigResolver) {
|
||||
func NewOidcController(r *authz.Router, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, oidcService *service.OidcService, appConfigService appconfig.AppConfigResolver) {
|
||||
oc := &OidcController{
|
||||
oidcService: oidcService,
|
||||
appConfigService: appConfigService,
|
||||
}
|
||||
|
||||
group.GET("/oidc/clients", authMiddleware.Add(), httpserver.Handle(oc.listClientsHandler))
|
||||
group.POST("/oidc/clients", authMiddleware.Add(), httpserver.Handle(oc.createClientHandler))
|
||||
group.GET("/oidc/clients/:id", authMiddleware.Add(), httpserver.Handle(oc.getClientHandler))
|
||||
group.GET("/oidc/clients/:id/meta", httpserver.Handle(oc.getClientMetaDataHandler))
|
||||
group.PUT("/oidc/clients/:id", authMiddleware.Add(), httpserver.Handle(oc.updateClientHandler))
|
||||
group.POST("/oidc/clients/:id/refresh", authMiddleware.Add(), httpserver.Handle(oc.refreshClientMetadataHandler))
|
||||
group.DELETE("/oidc/clients/:id", authMiddleware.Add(), httpserver.Handle(oc.deleteClientHandler))
|
||||
r.GET("/oidc/clients", authz.OidcClientsRead, httpserver.Handle(oc.listClientsHandler))
|
||||
r.POST("/oidc/clients", authz.OidcClientsWrite, httpserver.Handle(oc.createClientHandler))
|
||||
r.GET("/oidc/clients/:id", authz.OidcClientsRead, httpserver.Handle(oc.getClientHandler))
|
||||
r.Public().GET("/oidc/clients/:id/meta", httpserver.Handle(oc.getClientMetaDataHandler))
|
||||
r.PUT("/oidc/clients/:id", authz.OidcClientsWrite, httpserver.Handle(oc.updateClientHandler))
|
||||
r.POST("/oidc/clients/:id/refresh", authz.OidcClientsWrite, httpserver.Handle(oc.refreshClientMetadataHandler))
|
||||
r.DELETE("/oidc/clients/:id", authz.OidcClientsWrite, httpserver.Handle(oc.deleteClientHandler))
|
||||
|
||||
group.PUT("/oidc/clients/:id/allowed-user-groups", authMiddleware.Add(), httpserver.Handle(oc.updateAllowedUserGroupsHandler))
|
||||
group.GET("/oidc/clients/:id/secrets", authMiddleware.Add(), httpserver.Handle(oc.listClientSecretsHandler))
|
||||
group.POST("/oidc/clients/:id/secrets", authMiddleware.Add(), httpserver.Handle(oc.createClientSecretHandler))
|
||||
group.DELETE("/oidc/clients/:id/secrets/:secretId", authMiddleware.Add(), httpserver.Handle(oc.deleteClientSecretHandler))
|
||||
r.PUT("/oidc/clients/:id/allowed-user-groups", authz.OidcClientsWrite, httpserver.Handle(oc.updateAllowedUserGroupsHandler))
|
||||
r.GET("/oidc/clients/:id/secrets", authz.OidcClientsRead, httpserver.Handle(oc.listClientSecretsHandler))
|
||||
r.POST("/oidc/clients/:id/secrets", authz.OidcClientsWrite, httpserver.Handle(oc.createClientSecretHandler))
|
||||
r.DELETE("/oidc/clients/:id/secrets/:secretId", authz.OidcClientsWrite, httpserver.Handle(oc.deleteClientSecretHandler))
|
||||
|
||||
group.GET("/oidc/clients/:id/logo", httpserver.Handle(oc.getClientLogoHandler))
|
||||
group.DELETE("/oidc/clients/:id/logo", authMiddleware.Add(), httpserver.Handle(oc.deleteClientLogoHandler))
|
||||
group.POST("/oidc/clients/:id/logo", authMiddleware.Add(), fileSizeLimitMiddleware.Add(2<<20), httpserver.Handle(oc.updateClientLogoHandler))
|
||||
r.Public().GET("/oidc/clients/:id/logo", httpserver.Handle(oc.getClientLogoHandler))
|
||||
r.DELETE("/oidc/clients/:id/logo", authz.OidcClientsWrite, httpserver.Handle(oc.deleteClientLogoHandler))
|
||||
r.POST("/oidc/clients/:id/logo", authz.OidcClientsWrite, fileSizeLimitMiddleware.Add(2<<20), httpserver.Handle(oc.updateClientLogoHandler))
|
||||
|
||||
group.GET("/oidc/clients/:id/preview/:userId", authMiddleware.Add(), httpserver.Handle(oc.getClientPreviewHandler))
|
||||
// The preview renders a user's claims, so it is guarded by the user scope rather than the client scope
|
||||
r.GET("/oidc/clients/:id/preview/:userId", authz.UsersRead, httpserver.Handle(oc.getClientPreviewHandler))
|
||||
|
||||
group.GET("/oidc/users/me/authorized-clients", authMiddleware.WithAdminNotRequired().Add(), httpserver.Handle(oc.listOwnAuthorizedClientsHandler))
|
||||
group.GET("/oidc/users/:id/authorized-clients", authMiddleware.Add(), httpserver.Handle(oc.listAuthorizedClientsHandler))
|
||||
r.GET("/oidc/users/me/authorized-clients", authz.AccountApps, httpserver.Handle(oc.listOwnAuthorizedClientsHandler))
|
||||
r.GET("/oidc/users/:id/authorized-clients", authz.UsersRead, httpserver.Handle(oc.listAuthorizedClientsHandler))
|
||||
|
||||
group.DELETE("/oidc/users/me/authorized-clients/:clientId", authMiddleware.WithAdminNotRequired().Add(), httpserver.Handle(oc.revokeOwnClientAuthorizationHandler))
|
||||
|
||||
group.GET("/oidc/users/me/clients", authMiddleware.WithAdminNotRequired().Add(), httpserver.Handle(oc.listOwnAccessibleClientsHandler))
|
||||
r.DELETE("/oidc/users/me/authorized-clients/:clientId", authz.AccountApps, httpserver.Handle(oc.revokeOwnClientAuthorizationHandler))
|
||||
|
||||
r.GET("/oidc/users/me/clients", authz.AccountApps, httpserver.Handle(oc.listOwnAccessibleClientsHandler))
|
||||
}
|
||||
|
||||
type OidcController struct {
|
||||
@@ -173,7 +174,7 @@ func (oc *OidcController) createClientHandler(c *gin.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
client, createdSecret, err := oc.oidcService.CreateClient(c.Request.Context(), input, c.GetString("userID"), config.AutoCreateOIDCClientSecret.IsTrue())
|
||||
client, createdSecret, err := oc.oidcService.CreateClient(c.Request.Context(), input, authz.PrincipalFrom(c).UserID, config.AutoCreateOIDCClientSecret.IsTrue())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -480,7 +481,7 @@ func (oc *OidcController) updateAllowedUserGroupsHandler(c *gin.Context) error {
|
||||
// @Failure default {object} dto.ErrorDto "Error"
|
||||
// @Router /api/oidc/users/me/authorized-clients [get]
|
||||
func (oc *OidcController) listOwnAuthorizedClientsHandler(c *gin.Context) error {
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
return oc.listAuthorizedClients(c, userID)
|
||||
}
|
||||
|
||||
@@ -536,7 +537,7 @@ func (oc *OidcController) listAuthorizedClients(c *gin.Context, userID string) e
|
||||
func (oc *OidcController) revokeOwnClientAuthorizationHandler(c *gin.Context) error {
|
||||
clientID := c.Param("clientId")
|
||||
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
|
||||
err := oc.oidcService.RevokeAuthorizedClient(c.Request.Context(), userID, clientID)
|
||||
if err != nil {
|
||||
@@ -564,7 +565,7 @@ func (oc *OidcController) listOwnAccessibleClientsHandler(c *gin.Context) error
|
||||
searchTerm := c.Query("search")
|
||||
listRequestOptions := utils.ParseListRequestOptions(c)
|
||||
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
|
||||
clients, pagination, err := oc.oidcService.ListAccessibleOidcClients(c.Request.Context(), userID, searchTerm, listRequestOptions)
|
||||
if err != nil {
|
||||
@@ -612,7 +613,7 @@ func (oc *OidcController) getClientPreviewHandler(c *gin.Context) error {
|
||||
clientID,
|
||||
userID,
|
||||
strings.Split(scopes, " "),
|
||||
c.GetString("authenticationMethod"))
|
||||
authz.PrincipalFrom(c).AuthenticationMethod)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestImageUploadRoutesLimitRequestSize(t *testing.T) {
|
||||
apiKeyModule, err := apikey.New(t.Context(), apikey.Dependencies{DB: db, CleanupDisabled: true})
|
||||
require.NoError(t, err)
|
||||
|
||||
authMiddleware := middleware.NewAuthMiddleware(apiKeyModule, userService, jwtService)
|
||||
auth := middleware.NewAuthorization(apiKeyModule, userService, jwtService)
|
||||
fileSizeLimitMiddleware := middleware.NewFileSizeLimitMiddleware()
|
||||
|
||||
user := model.User{Username: "upload-admin", IsAdmin: true}
|
||||
@@ -54,9 +54,9 @@ func TestImageUploadRoutesLimitRequestSize(t *testing.T) {
|
||||
|
||||
router := gin.New()
|
||||
router.Use(middleware.NewErrorHandlerMiddleware().Add())
|
||||
apiGroup := router.Group("/api")
|
||||
NewUserController(apiGroup, authMiddleware, fileSizeLimitMiddleware, nil, userService, nil, func(c *gin.Context) { c.Next() })
|
||||
NewAppImagesController(apiGroup, authMiddleware, fileSizeLimitMiddleware, nil)
|
||||
apiRouter := auth.Router(router.Group("/api"))
|
||||
NewUserController(apiRouter, fileSizeLimitMiddleware, nil, userService, nil, func(c *gin.Context) { c.Next() })
|
||||
NewAppImagesController(apiRouter, fileSizeLimitMiddleware, nil)
|
||||
|
||||
routes := []string{
|
||||
"/api/users/user-id/profile-picture",
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
@@ -20,34 +21,33 @@ import (
|
||||
// @Summary User management controller
|
||||
// @Description Initializes all user-related API endpoints
|
||||
// @Tags Users
|
||||
func NewUserController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, appConfigService *appconfig.AppConfigService, userService *service.UserService, webAuthnService *webauthn.Module, updateOwnAccountRateLimit gin.HandlerFunc) {
|
||||
func NewUserController(r *authz.Router, fileSizeLimitMiddleware *middleware.FileSizeLimitMiddleware, appConfigService *appconfig.AppConfigService, userService *service.UserService, webAuthnService *webauthn.Module, updateOwnAccountRateLimit gin.HandlerFunc) {
|
||||
uc := UserController{
|
||||
appConfigService: appConfigService,
|
||||
userService: userService,
|
||||
webAuthnService: webAuthnService,
|
||||
}
|
||||
|
||||
group.GET("/users", authMiddleware.Add(), httpserver.Handle(uc.listUsersHandler))
|
||||
group.GET("/users/me", authMiddleware.WithAdminNotRequired().Add(), httpserver.Handle(uc.getCurrentUserHandler))
|
||||
group.GET("/users/:id", authMiddleware.Add(), httpserver.Handle(uc.getUserHandler))
|
||||
group.POST("/users", authMiddleware.Add(), httpserver.Handle(uc.createUserHandler))
|
||||
group.PUT("/users/:id", authMiddleware.Add(), httpserver.Handle(uc.updateUserHandler))
|
||||
group.GET("/users/:id/groups", authMiddleware.Add(), httpserver.Handle(uc.getUserGroupsHandler))
|
||||
group.GET("/users/:id/webauthn-credentials", authMiddleware.Add(), httpserver.Handle(uc.listUserWebauthnCredentialsHandler))
|
||||
// Updating the own account reports whether an email or username is already taken, so it is rate limited to slow down probing for existing users
|
||||
group.PUT("/users/me", authMiddleware.WithAdminNotRequired().Add(), updateOwnAccountRateLimit, httpserver.Handle(uc.updateCurrentUserHandler))
|
||||
group.DELETE("/users/:id", authMiddleware.Add(), httpserver.Handle(uc.deleteUserHandler))
|
||||
group.DELETE("/users/:id/webauthn-credentials/:credentialId", authMiddleware.Add(), httpserver.Handle(uc.deleteUserWebauthnCredentialHandler))
|
||||
r.GET("/users", authz.UsersRead, httpserver.Handle(uc.listUsersHandler))
|
||||
r.GET("/users/me", authz.AccountRead, httpserver.Handle(uc.getCurrentUserHandler))
|
||||
r.GET("/users/:id", authz.UsersRead, httpserver.Handle(uc.getUserHandler))
|
||||
r.POST("/users", authz.UsersWrite, httpserver.Handle(uc.createUserHandler))
|
||||
r.PUT("/users/:id", authz.UsersWrite, httpserver.Handle(uc.updateUserHandler))
|
||||
r.GET("/users/:id/groups", authz.UsersRead, httpserver.Handle(uc.getUserGroupsHandler))
|
||||
r.GET("/users/:id/webauthn-credentials", authz.UsersRead, httpserver.Handle(uc.listUserWebauthnCredentialsHandler))
|
||||
r.PUT("/users/me", authz.AccountWrite, updateOwnAccountRateLimit, httpserver.Handle(uc.updateCurrentUserHandler))
|
||||
r.DELETE("/users/:id", authz.UsersWrite, httpserver.Handle(uc.deleteUserHandler))
|
||||
r.DELETE("/users/:id/webauthn-credentials/:credentialId", authz.UsersWrite, httpserver.Handle(uc.deleteUserWebauthnCredentialHandler))
|
||||
|
||||
group.PUT("/users/:id/user-groups", authMiddleware.Add(), httpserver.Handle(uc.updateUserGroups))
|
||||
r.PUT("/users/:id/user-groups", authz.UsersWrite, httpserver.Handle(uc.updateUserGroups))
|
||||
|
||||
group.GET("/users/:id/profile-picture.png", httpserver.Handle(uc.getUserProfilePictureHandler))
|
||||
r.Public().GET("/users/:id/profile-picture.png", httpserver.Handle(uc.getUserProfilePictureHandler))
|
||||
|
||||
group.PUT("/users/:id/profile-picture", authMiddleware.Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(uc.updateUserProfilePictureHandler))
|
||||
group.PUT("/users/me/profile-picture", authMiddleware.WithAdminNotRequired().Add(), fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(uc.updateCurrentUserProfilePictureHandler))
|
||||
r.PUT("/users/:id/profile-picture", authz.UsersWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(uc.updateUserProfilePictureHandler))
|
||||
r.PUT("/users/me/profile-picture", authz.AccountWrite, fileSizeLimitMiddleware.Add(10<<20), httpserver.Handle(uc.updateCurrentUserProfilePictureHandler))
|
||||
|
||||
group.DELETE("/users/:id/profile-picture", authMiddleware.Add(), httpserver.Handle(uc.resetUserProfilePictureHandler))
|
||||
group.DELETE("/users/me/profile-picture", authMiddleware.WithAdminNotRequired().Add(), httpserver.Handle(uc.resetCurrentUserProfilePictureHandler))
|
||||
r.DELETE("/users/:id/profile-picture", authz.UsersWrite, httpserver.Handle(uc.resetUserProfilePictureHandler))
|
||||
r.DELETE("/users/me/profile-picture", authz.AccountWrite, httpserver.Handle(uc.resetCurrentUserProfilePictureHandler))
|
||||
}
|
||||
|
||||
type UserController struct {
|
||||
@@ -173,7 +173,7 @@ func (uc *UserController) getUserHandler(c *gin.Context) error {
|
||||
// @Failure default {object} dto.ErrorDto "Error"
|
||||
// @Router /api/users/me [get]
|
||||
func (uc *UserController) getCurrentUserHandler(c *gin.Context) error {
|
||||
user, err := uc.userService.GetUser(c.Request.Context(), c.GetString("userID"))
|
||||
user, err := uc.userService.GetUser(c.Request.Context(), authz.PrincipalFrom(c).UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -225,7 +225,7 @@ func (uc *UserController) deleteUserWebauthnCredentialHandler(c *gin.Context) er
|
||||
c.Param("credentialId"),
|
||||
c.ClientIP(),
|
||||
c.Request.UserAgent(),
|
||||
c.GetString("userID"),
|
||||
authz.PrincipalFrom(c).UserID,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -361,7 +361,7 @@ func (uc *UserController) updateUserProfilePictureHandler(c *gin.Context) error
|
||||
// @Failure default {object} dto.ErrorDto "Error"
|
||||
// @Router /api/users/me/profile-picture [put]
|
||||
func (uc *UserController) updateCurrentUserProfilePictureHandler(c *gin.Context) error {
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
fileHeader, err := httpserver.FormFile(c, "file")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -423,7 +423,7 @@ func (uc *UserController) updateUser(c *gin.Context, updateOwnUser bool) error {
|
||||
|
||||
var userID string
|
||||
if updateOwnUser {
|
||||
userID = c.GetString("userID")
|
||||
userID = authz.PrincipalFrom(c).UserID
|
||||
} else {
|
||||
userID = c.Param("id")
|
||||
}
|
||||
@@ -471,7 +471,7 @@ func (uc *UserController) resetUserProfilePictureHandler(c *gin.Context) error {
|
||||
// @Failure default {object} dto.ErrorDto "Error"
|
||||
// @Router /api/users/me/profile-picture [delete]
|
||||
func (uc *UserController) resetCurrentUserProfilePictureHandler(c *gin.Context) error {
|
||||
userID := c.GetString("userID")
|
||||
userID := authz.PrincipalFrom(c).UserID
|
||||
|
||||
if err := uc.userService.ResetProfilePicture(c.Request.Context(), userID); err != nil {
|
||||
return err
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/appconfig"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/httpserver"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/middleware"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/utils"
|
||||
)
|
||||
@@ -17,23 +17,20 @@ import (
|
||||
// @Summary User group management controller
|
||||
// @Description Initializes all user group-related API endpoints
|
||||
// @Tags User Groups
|
||||
func NewUserGroupController(group *gin.RouterGroup, authMiddleware *middleware.AuthMiddleware, appConfigService *appconfig.AppConfigService, userGroupService *service.UserGroupService) {
|
||||
func NewUserGroupController(r *authz.Router, appConfigService *appconfig.AppConfigService, userGroupService *service.UserGroupService) {
|
||||
ugc := UserGroupController{
|
||||
appConfigService: appConfigService,
|
||||
UserGroupService: userGroupService,
|
||||
}
|
||||
|
||||
userGroupsGroup := group.Group("/user-groups")
|
||||
userGroupsGroup.Use(authMiddleware.Add())
|
||||
{
|
||||
userGroupsGroup.GET("", httpserver.Handle(ugc.list))
|
||||
userGroupsGroup.GET("/:id", httpserver.Handle(ugc.get))
|
||||
userGroupsGroup.POST("", httpserver.Handle(ugc.create))
|
||||
userGroupsGroup.PUT("/:id", httpserver.Handle(ugc.update))
|
||||
userGroupsGroup.DELETE("/:id", httpserver.Handle(ugc.delete))
|
||||
userGroupsGroup.PUT("/:id/users", httpserver.Handle(ugc.updateUsers))
|
||||
userGroupsGroup.PUT("/:id/allowed-oidc-clients", httpserver.Handle(ugc.updateAllowedOidcClients))
|
||||
}
|
||||
userGroupsGroup := r.Group("/user-groups")
|
||||
userGroupsGroup.GET("", authz.GroupsRead, httpserver.Handle(ugc.list))
|
||||
userGroupsGroup.GET("/:id", authz.GroupsRead, httpserver.Handle(ugc.get))
|
||||
userGroupsGroup.POST("", authz.GroupsWrite, httpserver.Handle(ugc.create))
|
||||
userGroupsGroup.PUT("/:id", authz.GroupsWrite, httpserver.Handle(ugc.update))
|
||||
userGroupsGroup.DELETE("/:id", authz.GroupsWrite, httpserver.Handle(ugc.delete))
|
||||
userGroupsGroup.PUT("/:id/users", authz.GroupsWrite, httpserver.Handle(ugc.updateUsers))
|
||||
userGroupsGroup.PUT("/:id/allowed-oidc-clients", authz.GroupsWrite, httpserver.Handle(ugc.updateAllowedOidcClients))
|
||||
}
|
||||
|
||||
type UserGroupController struct {
|
||||
|
||||
Reference in New Issue
Block a user