mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-09-20 09:59:03 +02:00
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
co-authored by
Elias Schneider
parent
7c55bdf115
commit
1934efa84c
@@ -82,7 +82,6 @@ func (acc *AppConfigController) listAppConfigHandler(c *gin.Context) {
|
||||
configVariablesDto = append(configVariablesDto, dto.PublicAppConfigVariableDto{
|
||||
Key: "tracingEnabled",
|
||||
Value: strconv.FormatBool(tracing.FrontendTracingEnabled()),
|
||||
Type: "boolean",
|
||||
})
|
||||
|
||||
c.JSON(http.StatusOK, configVariablesDto)
|
||||
|
||||
@@ -31,6 +31,7 @@ func NewOidcController(group *gin.RouterGroup, authMiddleware *middleware.AuthMi
|
||||
group.GET("/oidc/clients/:id", authMiddleware.Add(), oc.getClientHandler)
|
||||
group.GET("/oidc/clients/:id/meta", oc.getClientMetaDataHandler)
|
||||
group.PUT("/oidc/clients/:id", authMiddleware.Add(), oc.updateClientHandler)
|
||||
group.POST("/oidc/clients/:id/refresh", authMiddleware.Add(), oc.refreshClientMetadataHandler)
|
||||
group.DELETE("/oidc/clients/:id", authMiddleware.Add(), oc.deleteClientHandler)
|
||||
|
||||
group.PUT("/oidc/clients/:id/allowed-user-groups", authMiddleware.Add(), oc.updateAllowedUserGroupsHandler)
|
||||
@@ -76,7 +77,6 @@ func (oc *OidcController) getClientMetaDataHandler(c *gin.Context) {
|
||||
clientDto := dto.OidcClientMetaDataDto{}
|
||||
err = dto.MapStruct(client, &clientDto)
|
||||
if err == nil {
|
||||
clientDto.HasDarkLogo = client.HasDarkLogo()
|
||||
c.JSON(http.StatusOK, clientDto)
|
||||
return
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func (oc *OidcController) listClientsHandler(c *gin.Context) {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
clientDto.HasDarkLogo = client.HasDarkLogo()
|
||||
|
||||
clientDto.AllowedUserGroupsCount, err = oc.oidcService.GetAllowedGroupsCountOfClient(c, client.ID)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
@@ -234,6 +234,30 @@ func (oc *OidcController) updateClientHandler(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, clientDto)
|
||||
}
|
||||
|
||||
// refreshClientMetadataHandler godoc
|
||||
// @Summary Refresh client metadata document
|
||||
// @Description Force a re-fetch of the OAuth Client ID Metadata Document for a CIMD client
|
||||
// @Tags OIDC
|
||||
// @Produce json
|
||||
// @Param id path string true "Client ID"
|
||||
// @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Refreshed client"
|
||||
// @Router /api/oidc/clients/{id}/refresh [post]
|
||||
func (oc *OidcController) refreshClientMetadataHandler(c *gin.Context) {
|
||||
client, err := oc.oidcService.RefreshClientMetadata(c.Request.Context(), c.Param("id"))
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var clientDto dto.OidcClientWithAllowedUserGroupsDto
|
||||
if err := dto.MapStruct(client, &clientDto); err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, clientDto)
|
||||
}
|
||||
|
||||
// createClientSecretHandler godoc
|
||||
// @Summary Create client secret
|
||||
// @Description Set or generate a new secret for an OIDC client
|
||||
|
||||
@@ -3,9 +3,7 @@ package controller
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
@@ -17,16 +15,10 @@ import (
|
||||
// @Summary OIDC Discovery controller
|
||||
// @Description Initializes OIDC discovery and JWKS endpoints
|
||||
// @Tags Well Known
|
||||
func NewWellKnownController(group *gin.RouterGroup, jwtService *service.JwtService) {
|
||||
wkc := &WellKnownController{jwtService: jwtService}
|
||||
|
||||
// Pre-compute the OIDC configuration document, which is static
|
||||
var err error
|
||||
wkc.oidcConfig, err = wkc.computeOIDCConfiguration()
|
||||
if err != nil {
|
||||
slog.Error("Failed to pre-compute OpenID Connect configuration document", slog.Any("error", err))
|
||||
os.Exit(1)
|
||||
return
|
||||
func NewWellKnownController(group *gin.RouterGroup, jwtService *service.JwtService, getCIMDURLAllowlist func() []string) {
|
||||
wkc := &WellKnownController{
|
||||
jwtService: jwtService,
|
||||
getCIMDURLAllowlist: getCIMDURLAllowlist,
|
||||
}
|
||||
|
||||
group.GET("/.well-known/jwks.json", wkc.jwksHandler)
|
||||
@@ -34,8 +26,8 @@ func NewWellKnownController(group *gin.RouterGroup, jwtService *service.JwtServi
|
||||
}
|
||||
|
||||
type WellKnownController struct {
|
||||
jwtService *service.JwtService
|
||||
oidcConfig []byte
|
||||
jwtService *service.JwtService
|
||||
getCIMDURLAllowlist func() []string
|
||||
}
|
||||
|
||||
// jwksHandler godoc
|
||||
@@ -62,7 +54,12 @@ func (wkc *WellKnownController) jwksHandler(c *gin.Context) {
|
||||
// @Success 200 {object} object "OpenID Connect configuration"
|
||||
// @Router /.well-known/openid-configuration [get]
|
||||
func (wkc *WellKnownController) openIDConfigurationHandler(c *gin.Context) {
|
||||
c.Data(http.StatusOK, "application/json; charset=utf-8", wkc.oidcConfig)
|
||||
oidcConfig, err := wkc.computeOIDCConfiguration()
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
c.Data(http.StatusOK, "application/json; charset=utf-8", oidcConfig)
|
||||
}
|
||||
|
||||
func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
||||
@@ -74,6 +71,11 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get key algorithm: %w", err)
|
||||
}
|
||||
cimdSupported := false
|
||||
if wkc.getCIMDURLAllowlist != nil {
|
||||
cimdSupported = len(wkc.getCIMDURLAllowlist()) > 0
|
||||
}
|
||||
|
||||
config := map[string]any{
|
||||
"issuer": appUrl,
|
||||
"authorization_endpoint": appUrl + "/authorize",
|
||||
@@ -98,6 +100,7 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
|
||||
"token_endpoint_auth_methods_supported": []string{"client_secret_basic", "client_secret_post", "none"},
|
||||
"pushed_authorization_request_endpoint": internalAppUrl + "/api/oidc/par",
|
||||
"require_pushed_authorization_requests": false,
|
||||
"client_id_metadata_document_supported": cimdSupported,
|
||||
}
|
||||
return json.Marshal(config)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/lestrrat-go/jwx/v3/jwa"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||
"github.com/pocket-id/pocket-id/backend/internal/service"
|
||||
jwkutils "github.com/pocket-id/pocket-id/backend/internal/utils/jwk"
|
||||
)
|
||||
|
||||
func newMinimalJwtService(t *testing.T) *service.JwtService {
|
||||
t.Helper()
|
||||
|
||||
key, err := jwkutils.GenerateKey(jwa.RS256().String(), "")
|
||||
require.NoError(t, err, "failed to generate test JWK key")
|
||||
|
||||
svc := &service.JwtService{}
|
||||
require.NoError(t, svc.SetKey(key), "failed to set JWK key on JwtService")
|
||||
return svc
|
||||
}
|
||||
|
||||
func TestClientIDMetadataDocumentDiscoveryFollowsAllowlist(t *testing.T) {
|
||||
origURL := common.EnvConfig.AppURL
|
||||
t.Cleanup(func() {
|
||||
common.EnvConfig.AppURL = origURL
|
||||
})
|
||||
|
||||
common.EnvConfig.AppURL = "https://test.example.com"
|
||||
jwtSvc := newMinimalJwtService(t)
|
||||
cimdURLAllowlist := []string(nil)
|
||||
wkc := &WellKnownController{
|
||||
jwtService: jwtSvc,
|
||||
getCIMDURLAllowlist: func() []string {
|
||||
return cimdURLAllowlist
|
||||
},
|
||||
}
|
||||
|
||||
parse := func(t *testing.T) map[string]any {
|
||||
t.Helper()
|
||||
raw, err := wkc.computeOIDCConfiguration()
|
||||
require.NoError(t, err)
|
||||
var cfg map[string]any
|
||||
require.NoError(t, json.Unmarshal(raw, &cfg))
|
||||
return cfg
|
||||
}
|
||||
|
||||
cimdURLAllowlist = []string{"https://client.example.com/**"}
|
||||
assert.Equal(t, true, parse(t)["client_id_metadata_document_supported"])
|
||||
|
||||
cimdURLAllowlist = nil
|
||||
assert.Equal(t, false, parse(t)["client_id_metadata_document_supported"])
|
||||
}
|
||||
Reference in New Issue
Block a user