mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-10 19:59:04 +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 (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ory/fosite"
|
||||
"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/utils"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/utils/cookie"
|
||||
@@ -35,10 +35,7 @@ func newAuthorizationHandler(
|
||||
|
||||
func (h *authorizationHandler) authorize(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
userID := c.GetString("userID")
|
||||
authenticationMethod := c.GetString("authenticationMethod")
|
||||
authenticationTime, _ := c.Get("authenticationTime")
|
||||
typedAuthenticationTime, _ := authenticationTime.(time.Time)
|
||||
principal := authz.PrincipalFrom(c)
|
||||
reauthenticationToken, _ := c.Cookie(cookie.ReauthenticationTokenCookieName)
|
||||
|
||||
// A request that resumes an interaction only carries the interaction ID; the original
|
||||
@@ -73,9 +70,9 @@ func (h *authorizationHandler) authorize(c *gin.Context) {
|
||||
}
|
||||
|
||||
authorization, err := h.authorizationService.authorize(ctx, authorizeInput{
|
||||
userID: userID,
|
||||
authenticationMethod: authenticationMethod,
|
||||
authenticationTime: typedAuthenticationTime,
|
||||
userID: principal.UserID,
|
||||
authenticationMethod: principal.AuthenticationMethod,
|
||||
authenticationTime: principal.AuthenticationTime,
|
||||
requester: ar,
|
||||
hasPushedAuthorizationRequest: hasPushedAuthorizationRequest,
|
||||
reauthenticationToken: reauthenticationToken,
|
||||
@@ -121,8 +118,7 @@ func (h *authorizationHandler) getInteractionSession(c *gin.Context) {
|
||||
|
||||
func (h *authorizationHandler) completeInteraction(c *gin.Context) {
|
||||
interactionID := c.Param("id")
|
||||
authenticationTime, _ := c.Get("authenticationTime")
|
||||
typedAuthenticationTime, _ := authenticationTime.(time.Time)
|
||||
principal := authz.PrincipalFrom(c)
|
||||
|
||||
var request completeInteractionRequest
|
||||
if err := httpserver.BindJSON(c, &request); err != nil {
|
||||
@@ -131,7 +127,7 @@ func (h *authorizationHandler) completeInteraction(c *gin.Context) {
|
||||
}
|
||||
|
||||
reauthenticationToken, _ := c.Cookie(cookie.ReauthenticationTokenCookieName)
|
||||
response, err := h.authorizationService.completeInteractionStep(c.Request.Context(), interactionID, c.GetString("userID"), request.Step, reauthenticationToken, typedAuthenticationTime, requestMetaFromGin(c))
|
||||
response, err := h.authorizationService.completeInteractionStep(c.Request.Context(), interactionID, principal.UserID, request.Step, reauthenticationToken, principal.AuthenticationTime, requestMetaFromGin(c))
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||
datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
||||
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||
@@ -167,8 +168,12 @@ func testAuthorizationHandlerPAR(t *testing.T, clientType string, tt authorizati
|
||||
rec := httptest.NewRecorder()
|
||||
router := gin.New()
|
||||
router.Handle(tt.method, "/authorize", func(c *gin.Context) {
|
||||
c.Set("userID", userID)
|
||||
c.Set("authenticationTime", time.Now().UTC().Add(-time.Minute))
|
||||
authz.SetPrincipal(c, &authz.Principal{
|
||||
Kind: authz.KindSession,
|
||||
UserID: userID,
|
||||
Scopes: authz.UserScopes(false, authz.KindSession),
|
||||
AuthenticationTime: time.Now().UTC().Add(-time.Minute),
|
||||
})
|
||||
handler.authorize(c)
|
||||
})
|
||||
router.ServeHTTP(rec, req)
|
||||
|
||||
@@ -4,11 +4,11 @@ import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ory/fosite"
|
||||
"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/utils/cookie"
|
||||
)
|
||||
|
||||
@@ -39,8 +39,7 @@ func (h *deviceHandler) authorizeDevice(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (h *deviceHandler) verifyDeviceCode(c *gin.Context) {
|
||||
authenticationTime, _ := c.Get("authenticationTime")
|
||||
typedAuthenticationTime, _ := authenticationTime.(time.Time)
|
||||
principal := authz.PrincipalFrom(c)
|
||||
reauthenticationToken, _ := c.Cookie(cookie.ReauthenticationTokenCookieName)
|
||||
|
||||
userCode := c.Query("code")
|
||||
@@ -52,9 +51,9 @@ func (h *deviceHandler) verifyDeviceCode(c *gin.Context) {
|
||||
err := h.deviceService.acceptDeviceCode(
|
||||
c.Request.Context(),
|
||||
userCode,
|
||||
c.GetString("userID"),
|
||||
c.GetString("authenticationMethod"),
|
||||
typedAuthenticationTime,
|
||||
principal.UserID,
|
||||
principal.AuthenticationMethod,
|
||||
principal.AuthenticationTime,
|
||||
reauthenticationToken,
|
||||
requestMetaFromGin(c),
|
||||
)
|
||||
@@ -77,7 +76,7 @@ func (h *deviceHandler) deviceCodeInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
deviceCodeInfo, err := h.deviceService.getDeviceCodeInfo(c.Request.Context(), userCode, c.GetString("userID"))
|
||||
deviceCodeInfo, err := h.deviceService.getDeviceCodeInfo(c.Request.Context(), userCode, authz.PrincipalFrom(c).UserID)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
|
||||
@@ -5,6 +5,7 @@ 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/utils/cookie"
|
||||
)
|
||||
@@ -28,7 +29,7 @@ func (h *endSessionHandler) endSession(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
callbackURL, err := h.endSessionService.endSession(c.Request.Context(), input, c.GetString("userID"))
|
||||
callbackURL, err := h.endSessionService.endSession(c.Request.Context(), input, authz.PrincipalFrom(c).UserID)
|
||||
if err != nil {
|
||||
slog.WarnContext(c.Request.Context(), "Error getting logout callback URL, the user has to confirm the logout manually", "error", err)
|
||||
c.Redirect(http.StatusFound, h.baseURL+"/logout")
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
francishost "github.com/italypaleale/francis/host"
|
||||
"github.com/lestrrat-go/jwx/v4/jwa"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/auditlogs"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/authz"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||
)
|
||||
|
||||
@@ -143,26 +143,26 @@ func (m *Module) RefreshClientMetadata(ctx context.Context, clientID string) (mo
|
||||
return m.cimdResolver.RefreshMetadataClient(ctx, clientID)
|
||||
}
|
||||
|
||||
func (m *Module) RegisterRoutes(rootGroup *gin.RouterGroup, apiGroup *gin.RouterGroup, optionalBrowserAuth gin.HandlerFunc, browserAuth gin.HandlerFunc) {
|
||||
rootGroup.GET("/authorize", optionalBrowserAuth, m.authorizationHandler.authorize)
|
||||
rootGroup.POST("/authorize", optionalBrowserAuth, m.authorizationHandler.authorize)
|
||||
func (m *Module) RegisterRoutes(root, api *authz.Router) {
|
||||
root.Optional().GET("/authorize", authz.AccountSession, m.authorizationHandler.authorize)
|
||||
root.Optional().POST("/authorize", authz.AccountSession, m.authorizationHandler.authorize)
|
||||
|
||||
apiGroup.GET("/oidc/interactions/:id", m.authorizationHandler.getInteractionSession)
|
||||
apiGroup.POST("/oidc/interactions/:id/complete", browserAuth, m.authorizationHandler.completeInteraction)
|
||||
api.Public().GET("/oidc/interactions/:id", m.authorizationHandler.getInteractionSession)
|
||||
api.POST("/oidc/interactions/:id/complete", authz.AccountSession, m.authorizationHandler.completeInteraction)
|
||||
|
||||
apiGroup.POST("/oidc/par", m.parHandler.pushedAuthorizationRequest)
|
||||
api.Public().POST("/oidc/par", m.parHandler.pushedAuthorizationRequest)
|
||||
|
||||
apiGroup.POST("/oidc/token", m.tokenHandler.token)
|
||||
api.Public().POST("/oidc/token", m.tokenHandler.token)
|
||||
|
||||
apiGroup.GET("/oidc/userinfo", m.userInfoHandler.userInfo)
|
||||
apiGroup.POST("/oidc/userinfo", m.userInfoHandler.userInfo)
|
||||
api.Public().GET("/oidc/userinfo", m.userInfoHandler.userInfo)
|
||||
api.Public().POST("/oidc/userinfo", m.userInfoHandler.userInfo)
|
||||
|
||||
apiGroup.POST("/oidc/introspect", m.introspectionHandler.introspectToken)
|
||||
api.Public().POST("/oidc/introspect", m.introspectionHandler.introspectToken)
|
||||
|
||||
apiGroup.GET("/oidc/end-session", optionalBrowserAuth, m.endSessionHandler.endSession)
|
||||
apiGroup.POST("/oidc/end-session", optionalBrowserAuth, m.endSessionHandler.endSession)
|
||||
api.Optional().GET("/oidc/end-session", authz.AccountSession, m.endSessionHandler.endSession)
|
||||
api.Optional().POST("/oidc/end-session", authz.AccountSession, m.endSessionHandler.endSession)
|
||||
|
||||
apiGroup.POST("/oidc/device/authorize", m.deviceHandler.authorizeDevice)
|
||||
apiGroup.POST("/oidc/device/verify", browserAuth, m.deviceHandler.verifyDeviceCode)
|
||||
apiGroup.GET("/oidc/device/info", browserAuth, m.deviceHandler.deviceCodeInfo)
|
||||
api.Public().POST("/oidc/device/authorize", m.deviceHandler.authorizeDevice)
|
||||
api.POST("/oidc/device/verify", authz.AccountSession, m.deviceHandler.verifyDeviceCode)
|
||||
api.GET("/oidc/device/info", authz.AccountSession, m.deviceHandler.deviceCodeInfo)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user