From 9af1abef900dc4100b0ac0b757a4afa73cd22583 Mon Sep 17 00:00:00 2001 From: jwijenbergh Date: Wed, 27 Sep 2023 16:07:15 +0200 Subject: OAuth: Correctly pass Redirect URI to token request --- internal/oauth/oauth.go | 57 ++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/internal/oauth/oauth.go b/internal/oauth/oauth.go index 6de3ac7..3d5930b 100644 --- a/internal/oauth/oauth.go +++ b/internal/oauth/oauth.go @@ -110,6 +110,9 @@ type exchangeSession struct { // Verifier is the preimage of the challenge Verifier string + // RedirectURI is the passed redirect URI + RedirectURI string + // Listener is the listener where the servers 'listens' on Listener net.Listener @@ -132,14 +135,13 @@ func (oauth *OAuth) AccessToken(ctx context.Context) (string, error) { // If it was unsuccessful it returns an error. // @see https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-07.html#section-8.4.2 // "Loopback Interface Redirection". -func (oauth *OAuth) setupListener() error { +func (oauth *OAuth) setupListener() (net.Listener, error) { // create a listener lst, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { - return errors.WrapPrefix(err, "net.Listen failed", 0) + return nil, errors.WrapPrefix(err, "net.Listen failed", 0) } - oauth.session.Listener = lst - return nil + return lst, nil } // tokensWithCallback gets the OAuth tokens using a local web server @@ -228,17 +230,12 @@ func (oauth *OAuth) tokensWithAuthCode(ctx context.Context, authCode string) err // so that the server can verify that we are the actual owner of the authorization code u := oauth.TokenURL - port, err := oauth.ListenerPort() - if err != nil { - return err - } - data := url.Values{ "client_id": {oauth.ClientID}, "code": {authCode}, "code_verifier": {oauth.session.Verifier}, "grant_type": {"authorization_code"}, - "redirect_uri": {fmt.Sprintf("http://127.0.0.1:%d/callback", port)}, + "redirect_uri": {oauth.session.RedirectURI}, } h := http.Header{ "content-type": {"application/x-www-form-urlencoded"}, @@ -436,15 +433,6 @@ func (oauth *OAuth) Init(clientID string, iss string, baseAuthorizationURL strin oauth.TokenURL = tokenURL } -// ListenerPort gets the listener for the OAuth web server -// It returns the port as an integer and an error if there is any. -func (oauth *OAuth) ListenerPort() (int, error) { - if oauth.session.Listener == nil { - return 0, errors.New("failed to get listener port") - } - return oauth.session.Listener.Addr().(*net.TCPAddr).Port, nil -} - // AuthURL gets the authorization url to start the OAuth procedure. func (oauth *OAuth) AuthURL(name string, postProcessAuth func(string) string, cr string) (string, error) { // Update the client ID @@ -466,27 +454,28 @@ func (oauth *OAuth) AuthURL(name string, postProcessAuth func(string) string, cr oauth.UpdateTokens(Token{}) // Fill the struct with the necessary fields filled for the next call to getting the HTTP client - oauth.session = exchangeSession{ - ISS: oauth.ISS, - State: state, - Verifier: v, - ErrChan: make(chan error), - } - - // set up the listener to get the redirect URI - if err = oauth.setupListener(); err != nil { - return "", errors.WrapPrefix(err, "oauth.setupListener error", 0) - } - red := cr + + // no custom redirect URI defined, we setup our own + var l net.Listener if cr == "" { - // Get the listener port - port, err := oauth.ListenerPort() + // set up the listener to get the redirect URI + l, err = oauth.setupListener() if err != nil { - return "", errors.WrapPrefix(err, "oauth.ListenerPort error", 0) + return "", errors.WrapPrefix(err, "oauth.setupListener error", 0) } + port := l.Addr().(*net.TCPAddr).Port + // see https://git.sr.ht/~fkooman/vpn-user-portal/tree/v3/item/src/OAuth/VpnClientDb.php red = fmt.Sprintf("http://127.0.0.1:%d/callback", port) } + oauth.session = exchangeSession{ + ISS: oauth.ISS, + State: state, + Verifier: v, + ErrChan: make(chan error), + RedirectURI: red, + Listener: l, + } params := map[string]string{ "client_id": name, -- cgit v1.2.3