summaryrefslogtreecommitdiffstats
path: root/services/auth/source/oauth2/source_callout.go
diff options
context:
space:
mode:
Diffstat (limited to 'services/auth/source/oauth2/source_callout.go')
-rw-r--r--services/auth/source/oauth2/source_callout.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/services/auth/source/oauth2/source_callout.go b/services/auth/source/oauth2/source_callout.go
new file mode 100644
index 0000000..f95a80f
--- /dev/null
+++ b/services/auth/source/oauth2/source_callout.go
@@ -0,0 +1,68 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package oauth2
+
+import (
+ "net/http"
+ "net/url"
+
+ "github.com/markbates/goth"
+ "github.com/markbates/goth/gothic"
+)
+
+// Callout redirects request/response pair to authenticate against the provider
+func (source *Source) Callout(request *http.Request, response http.ResponseWriter, codeChallengeS256 string) error {
+ // not sure if goth is thread safe (?) when using multiple providers
+ request.Header.Set(ProviderHeaderKey, source.authSource.Name)
+
+ var querySuffix string
+ if codeChallengeS256 != "" {
+ querySuffix = "&" + url.Values{
+ "code_challenge_method": []string{"S256"},
+ "code_challenge": []string{codeChallengeS256},
+ }.Encode()
+ }
+
+ // don't use the default gothic begin handler to prevent issues when some error occurs
+ // normally the gothic library will write some custom stuff to the response instead of our own nice error page
+ // gothic.BeginAuthHandler(response, request)
+
+ gothRWMutex.RLock()
+ defer gothRWMutex.RUnlock()
+
+ url, err := gothic.GetAuthURL(response, request)
+ if err == nil {
+ // hacky way to set the code_challenge, but no better way until
+ // https://github.com/markbates/goth/issues/516 is resolved
+ http.Redirect(response, request, url+querySuffix, http.StatusTemporaryRedirect)
+ }
+ return err
+}
+
+// Callback handles OAuth callback, resolve to a goth user and send back to original url
+// this will trigger a new authentication request, but because we save it in the session we can use that
+func (source *Source) Callback(request *http.Request, response http.ResponseWriter, codeVerifier string) (goth.User, error) {
+ // not sure if goth is thread safe (?) when using multiple providers
+ request.Header.Set(ProviderHeaderKey, source.authSource.Name)
+
+ if codeVerifier != "" {
+ // hacky way to set the code_verifier...
+ // Will be picked up inside CompleteUserAuth: params := req.URL.Query()
+ // https://github.com/markbates/goth/pull/474/files
+ request = request.Clone(request.Context())
+ q := request.URL.Query()
+ q.Add("code_verifier", codeVerifier)
+ request.URL.RawQuery = q.Encode()
+ }
+
+ gothRWMutex.RLock()
+ defer gothRWMutex.RUnlock()
+
+ user, err := gothic.CompleteUserAuth(response, request)
+ if err != nil {
+ return user, err
+ }
+
+ return user, nil
+}