give users more control over how PKCE challenge codes are generated
This commit is contained in:
parent
a63fbee93d
commit
50d331577c
2 changed files with 29 additions and 7 deletions
|
@ -43,7 +43,7 @@ func main() {
|
||||||
state := func() string {
|
state := func() string {
|
||||||
return uuid.New().String()
|
return uuid.New().String()
|
||||||
}
|
}
|
||||||
token := cli.CodeFlow(relyingParty, callbackPath, port, state)
|
token := cli.CodeFlow(ctx, relyingParty, callbackPath, port, state)
|
||||||
|
|
||||||
client := github.NewClient(relyingParty.OAuthConfig().Client(ctx, token.Token))
|
client := github.NewClient(relyingParty.OAuthConfig().Client(ctx, token.Token))
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ type RelyingParty interface {
|
||||||
//IsPKCE returns if authorization is done using `Authorization Code Flow with Proof Key for Code Exchange (PKCE)`
|
//IsPKCE returns if authorization is done using `Authorization Code Flow with Proof Key for Code Exchange (PKCE)`
|
||||||
IsPKCE() bool
|
IsPKCE() bool
|
||||||
|
|
||||||
|
//PKCECodeGenerator controls how PKCE challenge codes are generated
|
||||||
|
PKCECodeGenerator() PKCECodeGenerator
|
||||||
|
|
||||||
//CookieHandler returns a http cookie handler used for various state transfer cookies
|
//CookieHandler returns a http cookie handler used for various state transfer cookies
|
||||||
CookieHandler() *utils.CookieHandler
|
CookieHandler() *utils.CookieHandler
|
||||||
|
|
||||||
|
@ -61,11 +64,15 @@ type RelyingParty interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorHandler func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string)
|
type ErrorHandler func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string)
|
||||||
|
type PKCECodeGenerator func() string
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultErrorHandler ErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
DefaultErrorHandler ErrorHandler = func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
||||||
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
|
http.Error(w, errorType+": "+errorDesc, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
DefaultPKCECodeGenerator PKCECodeGenerator = func() string {
|
||||||
|
return base64.RawURLEncoding.EncodeToString([]byte(uuid.New().String()))
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type relyingParty struct {
|
type relyingParty struct {
|
||||||
|
@ -74,6 +81,7 @@ type relyingParty struct {
|
||||||
oauthConfig *oauth2.Config
|
oauthConfig *oauth2.Config
|
||||||
oauth2Only bool
|
oauth2Only bool
|
||||||
pkce bool
|
pkce bool
|
||||||
|
pkceCodeGenerator PKCECodeGenerator
|
||||||
|
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
cookieHandler *utils.CookieHandler
|
cookieHandler *utils.CookieHandler
|
||||||
|
@ -96,6 +104,10 @@ func (rp *relyingParty) IsPKCE() bool {
|
||||||
return rp.pkce
|
return rp.pkce
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rp *relyingParty) PKCECodeGenerator() PKCECodeGenerator {
|
||||||
|
return rp.pkceCodeGenerator
|
||||||
|
}
|
||||||
|
|
||||||
func (rp *relyingParty) CookieHandler() *utils.CookieHandler {
|
func (rp *relyingParty) CookieHandler() *utils.CookieHandler {
|
||||||
return rp.cookieHandler
|
return rp.cookieHandler
|
||||||
}
|
}
|
||||||
|
@ -195,9 +207,19 @@ func WithCookieHandler(cookieHandler *utils.CookieHandler) Option {
|
||||||
//it also sets a `CookieHandler` for securing the various redirects
|
//it also sets a `CookieHandler` for securing the various redirects
|
||||||
//and exchanging the code challenge
|
//and exchanging the code challenge
|
||||||
func WithPKCE(cookieHandler *utils.CookieHandler) Option {
|
func WithPKCE(cookieHandler *utils.CookieHandler) Option {
|
||||||
|
return WithCallerDefinedPKCE(cookieHandler, DefaultPKCECodeGenerator)
|
||||||
|
}
|
||||||
|
|
||||||
|
//WithCallerDefinedPKCE works much the same as WithPKCE, but allows the caller
|
||||||
|
//to specify how PKCE challenge codes should be generated. Some OIDC providers
|
||||||
|
//place additional requirements on challenge codes - this allows the caller
|
||||||
|
//to meet them if possible. Note that a challenge code should be at least 36 characters
|
||||||
|
//in length and securely generated.
|
||||||
|
func WithCallerDefinedPKCE(cookieHandler *utils.CookieHandler, codeGenerator PKCECodeGenerator) Option {
|
||||||
return func(rp *relyingParty) error {
|
return func(rp *relyingParty) error {
|
||||||
rp.pkce = true
|
rp.pkce = true
|
||||||
rp.cookieHandler = cookieHandler
|
rp.cookieHandler = cookieHandler
|
||||||
|
rp.pkceCodeGenerator = codeGenerator
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,7 +311,7 @@ func AuthURLHandler(stateFn func() string, rp RelyingParty) http.HandlerFunc {
|
||||||
|
|
||||||
//GenerateAndStoreCodeChallenge generates a PKCE code challenge and stores its verifier into a secure cookie
|
//GenerateAndStoreCodeChallenge generates a PKCE code challenge and stores its verifier into a secure cookie
|
||||||
func GenerateAndStoreCodeChallenge(w http.ResponseWriter, rp RelyingParty) (string, error) {
|
func GenerateAndStoreCodeChallenge(w http.ResponseWriter, rp RelyingParty) (string, error) {
|
||||||
codeVerifier := base64.RawURLEncoding.EncodeToString([]byte(uuid.New().String()))
|
codeVerifier := rp.PKCECodeGenerator()()
|
||||||
if err := rp.CookieHandler().SetCookie(w, pkceCode, codeVerifier); err != nil {
|
if err := rp.CookieHandler().SetCookie(w, pkceCode, codeVerifier); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue