mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-08-19 11:26:25 +00:00
feat: add support for declaritive client secret configuration (#1619)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -234,14 +236,22 @@ func (oc *OidcController) updateClientHandler(c *gin.Context) {
|
||||
|
||||
// createClientSecretHandler godoc
|
||||
// @Summary Create client secret
|
||||
// @Description Generate a new secret for an OIDC client
|
||||
// @Description Set or generate a new secret for an OIDC client
|
||||
// @Tags OIDC
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "Client ID"
|
||||
// @Param payload body dto.OidcClientSecretDto false "Client secret"
|
||||
// @Success 200 {object} object "{ \"secret\": \"string\" }"
|
||||
// @Router /api/oidc/clients/{id}/secret [post]
|
||||
func (oc *OidcController) createClientSecretHandler(c *gin.Context) {
|
||||
secret, err := oc.oidcService.CreateClientSecret(c.Request.Context(), c.Param("id"))
|
||||
var input dto.OidcClientSecretDto
|
||||
if err := c.ShouldBindJSON(&input); err != nil && !errors.Is(err, io.EOF) {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
secret, err := oc.oidcService.CreateClientSecret(c.Request.Context(), c.Param("id"), input)
|
||||
if err != nil {
|
||||
_ = c.Error(err)
|
||||
return
|
||||
|
||||
@@ -59,6 +59,10 @@ type OidcClientCreateDto struct {
|
||||
ID string `json:"id" binding:"omitempty,client_id,min=2,max=128"`
|
||||
}
|
||||
|
||||
type OidcClientSecretDto struct {
|
||||
Secret string `json:"secret" binding:"omitempty,min=16,printascii"`
|
||||
}
|
||||
|
||||
type OidcClientCredentialsDto struct {
|
||||
FederatedIdentities []OidcClientFederatedIdentityDto `json:"federatedIdentities,omitempty"`
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ func (s *OidcService) DeleteClient(ctx context.Context, clientID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *OidcService) CreateClientSecret(ctx context.Context, clientID string) (string, error) {
|
||||
func (s *OidcService) CreateClientSecret(ctx context.Context, clientID string, input dto.OidcClientSecretDto) (string, error) {
|
||||
tx := s.db.Begin()
|
||||
defer func() {
|
||||
tx.Rollback()
|
||||
@@ -281,9 +281,12 @@ func (s *OidcService) CreateClientSecret(ctx context.Context, clientID string) (
|
||||
return "", err
|
||||
}
|
||||
|
||||
clientSecret, err := utils.GenerateRandomAlphanumericString(32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
clientSecret := input.Secret
|
||||
if clientSecret == "" {
|
||||
clientSecret, err = utils.GenerateRandomAlphanumericString(32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
hashedSecret, err := bcrypt.GenerateFromPassword([]byte(clientSecret), bcrypt.DefaultCost)
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -499,6 +501,29 @@ func TestOidcService_CreateClient_withoutDescription(t *testing.T) {
|
||||
assert.Empty(t, fetched.Description)
|
||||
}
|
||||
|
||||
func TestOidcService_CreateClientSecret_withCustomSecret(t *testing.T) {
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
|
||||
s, err := NewOidcService(db, nil, nil, nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := model.OidcClient{Name: "Test Client"}
|
||||
err = db.Create(&client).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
customSecret := "custom-client-secret-with-a-minimum-length"
|
||||
input := dto.OidcClientSecretDto{Secret: customSecret}
|
||||
|
||||
secret, err := s.CreateClientSecret(t.Context(), client.ID, input)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, customSecret, secret)
|
||||
|
||||
var fetched model.OidcClient
|
||||
err = db.First(&fetched, "id = ?", client.ID).Error
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, bcrypt.CompareHashAndPassword([]byte(fetched.Secret), []byte(customSecret)))
|
||||
}
|
||||
|
||||
func TestOidcService_UpdateClient_description(t *testing.T) {
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user