mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-02-04 15:04:43 +00:00
fix: decode URL-encoded client ID and secret in Basic auth (#1263)
This commit is contained in:
@@ -164,7 +164,7 @@ func (oc *OidcController) createTokensHandler(c *gin.Context) {
|
|||||||
|
|
||||||
// Client id and secret can also be passed over the Authorization header
|
// Client id and secret can also be passed over the Authorization header
|
||||||
if input.ClientID == "" && input.ClientSecret == "" {
|
if input.ClientID == "" && input.ClientSecret == "" {
|
||||||
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
|
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens, err := oc.oidcService.CreateTokens(c.Request.Context(), input)
|
tokens, err := oc.oidcService.CreateTokens(c.Request.Context(), input)
|
||||||
@@ -322,7 +322,7 @@ func (oc *OidcController) introspectTokenHandler(c *gin.Context) {
|
|||||||
creds service.ClientAuthCredentials
|
creds service.ClientAuthCredentials
|
||||||
ok bool
|
ok bool
|
||||||
)
|
)
|
||||||
creds.ClientID, creds.ClientSecret, ok = c.Request.BasicAuth()
|
creds.ClientID, creds.ClientSecret, ok = utils.OAuthClientBasicAuth(c.Request)
|
||||||
if !ok {
|
if !ok {
|
||||||
// If there's no basic auth, check if we have a bearer token
|
// If there's no basic auth, check if we have a bearer token
|
||||||
bearer, ok := utils.BearerAuth(c.Request)
|
bearer, ok := utils.BearerAuth(c.Request)
|
||||||
@@ -659,7 +659,7 @@ func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) {
|
|||||||
|
|
||||||
// Client id and secret can also be passed over the Authorization header
|
// Client id and secret can also be passed over the Authorization header
|
||||||
if input.ClientID == "" && input.ClientSecret == "" {
|
if input.ClientID == "" && input.ClientSecret == "" {
|
||||||
input.ClientID, input.ClientSecret, _ = c.Request.BasicAuth()
|
input.ClientID, input.ClientSecret, _ = utils.OAuthClientBasicAuth(c.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := oc.oidcService.CreateDeviceAuthorization(c.Request.Context(), input)
|
response, err := oc.oidcService.CreateDeviceAuthorization(c.Request.Context(), input)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -21,6 +22,27 @@ func BearerAuth(r *http.Request) (string, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OAuthClientBasicAuth returns the OAuth client ID and secret provided in the request's
|
||||||
|
// Authorization header, if present. See RFC 6749, Section 2.3.
|
||||||
|
func OAuthClientBasicAuth(r *http.Request) (clientID, clientSecret string, ok bool) {
|
||||||
|
clientID, clientSecret, ok = r.BasicAuth()
|
||||||
|
if !ok {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientID, err := url.QueryUnescape(clientID)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSecret, err = url.QueryUnescape(clientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientID, clientSecret, true
|
||||||
|
}
|
||||||
|
|
||||||
// SetCacheControlHeader sets the Cache-Control header for the response.
|
// SetCacheControlHeader sets the Cache-Control header for the response.
|
||||||
func SetCacheControlHeader(ctx *gin.Context, maxAge, staleWhileRevalidate time.Duration) {
|
func SetCacheControlHeader(ctx *gin.Context, maxAge, staleWhileRevalidate time.Duration) {
|
||||||
_, ok := ctx.GetQuery("skipCache")
|
_, ok := ctx.GetQuery("skipCache")
|
||||||
|
|||||||
@@ -63,3 +63,62 @@ func TestBearerAuth(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOAuthClientBasicAuth(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
authHeader string
|
||||||
|
expectedClientID string
|
||||||
|
expectedClientSecret string
|
||||||
|
expectedOk bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid client ID and secret in header (example from RFC 6749)",
|
||||||
|
authHeader: "Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3",
|
||||||
|
expectedClientID: "s6BhdRkqt3",
|
||||||
|
expectedClientSecret: "7Fjfp0ZBr1KtDRbnfVdmIw",
|
||||||
|
expectedOk: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid client ID and secret in header (escaped values)",
|
||||||
|
authHeader: "Basic ZTUwOTcyYmQtNmUzMi00OTU3LWJhZmMtMzU0MTU3ZjI1NDViOislMjUlMjYlMkIlQzIlQTMlRTIlODIlQUM=",
|
||||||
|
expectedClientID: "e50972bd-6e32-4957-bafc-354157f2545b",
|
||||||
|
// This is the example string from RFC 6749, Appendix B.
|
||||||
|
expectedClientSecret: " %&+£€",
|
||||||
|
expectedOk: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty auth header",
|
||||||
|
authHeader: "",
|
||||||
|
expectedClientID: "",
|
||||||
|
expectedClientSecret: "",
|
||||||
|
expectedOk: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basic prefix only",
|
||||||
|
authHeader: "Basic ",
|
||||||
|
expectedClientID: "",
|
||||||
|
expectedClientSecret: "",
|
||||||
|
expectedOk: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "http://example.com", nil)
|
||||||
|
require.NoError(t, err, "Failed to create request")
|
||||||
|
|
||||||
|
if tt.authHeader != "" {
|
||||||
|
req.Header.Set("Authorization", tt.authHeader)
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId, clientSecret, ok := OAuthClientBasicAuth(req)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.expectedOk, ok)
|
||||||
|
|
||||||
|
if tt.expectedOk {
|
||||||
|
assert.Equal(t, tt.expectedClientID, clientId)
|
||||||
|
assert.Equal(t, tt.expectedClientSecret, clientSecret)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user