Cleanup of callback script and service logs.

Updated readme with setup instructions
This commit is contained in:
donskifarrell 2021-09-16 08:09:51 +08:00
parent ccb516f8ee
commit d22da69e2a
2 changed files with 116 additions and 58 deletions

68
README.md Normal file
View File

@ -0,0 +1,68 @@
# SCM OAuth Provider
This is a lightweight Go server for handling OAuth flows with Gitea, Gitlab, Bitbucket, GitHub.
> Note: My primary use case is providing OAuth between Gitea and NetlifyCMS. Other SCMs are untested as of now.
## Setup
Open the repo and build the service:
```
go build -o oauth-provider .
```
Deploy the binary to your server.
> Dockerfile is coming soon
## Config
The service needs some minimal configuration set before it can run.
On the server or the location you are running the service, create a config file:
```
mkdir ./env
touch ./env/config
```
The config file is TOML based. You can see a complete example in this repo at `./env/sample.config`
```
[runtime]
# Not used anywhere yet, for information only
environment="development"
[server]
# The hostname to serve from; Your external app will connect to the OAuth provider via this URL
host="localhost"
# The port to serve from; Used in conjunction with [server.host] to create a complete URL
port="3000"
# Used with OAuth provider sessions
sessionSecret="super-secret"
```
For each CMS, there are some required settings:
```
[gitea]
# OAuth Key and Secret generated on the SCM site
key="<KEY>"
secret="<SECRET>"
# URL of the SCM instance
baseUrl="https://gitea.company.com"
# URI of the authorize endpoint (e.g for Gitea, this is shown when creating the OAuth application)
authUri="login/oauth/authorize"
# URI of the access_token endpoint (e.g for Gitea, this is shown when creating the OAuth application)
accessTokenUri="login/oauth/access_token"
# URI of the authorize endpoint if overridden (e.g for Gitea, this is shown when creating the OAuth application)
userUri="api/v1/user"
# Callback URL for the SCM, where it will redirect the user after they authorise. This needs to match what was given when creating the OAuth application.
callbackUri="http://localhost:3000/callback/gitea"
```
### Credits
Inspiration taken from https://github.com/igk1972/netlify-cms-oauth-provider-go

106
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"net" "net"
@ -21,8 +22,18 @@ import (
) )
var ( var (
serviceName = "netlify-cms-oauth-provider" serviceName = "oauth-provider"
msgTemplate = `<!DOCTYPE html><html><head></head><body>{{.}}</body></html>` msgTemplate = `<!DOCTYPE html><html><head></head><body>{{.}}</body></html>`
resTemplate = `
<!DOCTYPE html><html><head></head><body>
<script>
function recieveMsg(e) {
window.opener.postMessage("{{.OAuthResult}}", e.origin);
}
window.addEventListener("message", recieveMsg, false);
window.opener.postMessage("{{.Provider}}", "*");
</script>
</body></html>`
log *logrus.Entry log *logrus.Entry
config *viper.Viper config *viper.Viper
@ -45,7 +56,7 @@ func initProviders() {
) )
type settings struct { type settings struct {
key, secret, baseURL, callbackURL, authURI, accessTokenURI, userURI string key, secret, BaseURL, CallbackURL, AuthURI, AccessTokenURI, UserURI string
} }
log.Info("initialising providers") log.Info("initialising providers")
@ -55,11 +66,11 @@ func initProviders() {
return settings{ return settings{
key: config.GetString(name + ".key"), key: config.GetString(name + ".key"),
secret: config.GetString(name + ".secret"), secret: config.GetString(name + ".secret"),
baseURL: baseURL, BaseURL: baseURL,
authURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".authURI")), AuthURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".authURI")),
accessTokenURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".accessTokenURI")), AccessTokenURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".accessTokenURI")),
userURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".userURI")), UserURI: fmt.Sprintf("%s/%s", baseURL, config.GetString(name+".userURI")),
callbackURL: config.GetString(name + ".callbackURI"), CallbackURL: config.GetString(name + ".callbackURI"),
} }
} }
@ -67,11 +78,12 @@ func initProviders() {
log.Info("- adding gitea provider") log.Info("- adding gitea provider")
var p goth.Provider var p goth.Provider
s := getProviderSetings("gitea") s := getProviderSetings("gitea")
if s.authURI != "" { if s.AuthURI != "" {
log.Infof("-- with custom settings %+v", s) out, _ := json.MarshalIndent(s, "", " ")
p = gitea.NewCustomisedURL(s.key, s.secret, s.callbackURL, s.authURI, s.accessTokenURI, s.userURI) log.Infof("-- with custom settings %s", string(out))
p = gitea.NewCustomisedURL(s.key, s.secret, s.CallbackURL, s.AuthURI, s.AccessTokenURI, s.UserURI)
} else { } else {
p = gitea.New(s.key, s.secret, s.callbackURL) p = gitea.New(s.key, s.secret, s.CallbackURL)
} }
providers = append(providers, p) providers = append(providers, p)
} }
@ -80,11 +92,12 @@ func initProviders() {
log.Info("- adding gitlab provider") log.Info("- adding gitlab provider")
var p goth.Provider var p goth.Provider
s := getProviderSetings("gitlab") s := getProviderSetings("gitlab")
if s.authURI != "" { if s.AuthURI != "" {
log.Infof("-- with custom settings %+v", s) out, _ := json.MarshalIndent(s, "", " ")
p = gitlab.NewCustomisedURL(s.key, s.secret, s.callbackURL, s.authURI, s.accessTokenURI, s.userURI) log.Infof("-- with custom settings %s", string(out))
p = gitlab.NewCustomisedURL(s.key, s.secret, s.CallbackURL, s.AuthURI, s.AccessTokenURI, s.UserURI)
} else { } else {
p = gitlab.New(s.key, s.secret, s.callbackURL) p = gitlab.New(s.key, s.secret, s.CallbackURL)
} }
providers = append(providers, p) providers = append(providers, p)
} }
@ -93,7 +106,7 @@ func initProviders() {
log.Info("- adding github provider") log.Info("- adding github provider")
var p goth.Provider var p goth.Provider
s := getProviderSetings("github") s := getProviderSetings("github")
p = github.New(s.key, s.secret, s.callbackURL) p = github.New(s.key, s.secret, s.CallbackURL)
providers = append(providers, p) providers = append(providers, p)
} }
@ -101,7 +114,7 @@ func initProviders() {
log.Info("- adding bitbucket provider") log.Info("- adding bitbucket provider")
var p goth.Provider var p goth.Provider
s := getProviderSetings("bitbucket") s := getProviderSetings("bitbucket")
p = bitbucket.New(s.key, s.secret, s.callbackURL) p = bitbucket.New(s.key, s.secret, s.CallbackURL)
providers = append(providers, p) providers = append(providers, p)
} }
@ -109,37 +122,6 @@ func initProviders() {
goth.UseProviders(providers...) goth.UseProviders(providers...)
} }
const (
script = `<!DOCTYPE html><html><head><script>
if (!window.opener) {
window.opener = {
postMessage: function(action, origin) {
console.log(action, origin);
}
}
}
(function(status, provider, result) {
function recieveMessage(e) {
console.log("Recieve message:", e);
// send message to main window with da app
console.log("Sending message:", "authorization:" + provider + ":" + status + ":" + result, e.origin)
window.opener.postMessage(
"authorization:" + provider + ":" + status + ":" + result,
e.origin
);
}
window.addEventListener("message", recieveMessage, false);
// Start handshare with parent
console.log("Sending message:", "authorizing:" + provider, "*")
window.opener.postMessage(
"authorizing:" + provider,
"*"
);
})(%#v, %#v, %#v)
</script></head><body></body></html>`
)
func main() { func main() {
log = logrus.New().WithFields(logrus.Fields{ log = logrus.New().WithFields(logrus.Fields{
"service": serviceName, "service": serviceName,
@ -157,6 +139,8 @@ func main() {
}) })
r.HandleFunc("/callback/{provider}", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/callback/{provider}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
provider, err := gothic.GetProviderName(r) provider, err := gothic.GetProviderName(r)
if err != nil { if err != nil {
log.Errorf("callback: GetProviderName failed %v", err) log.Errorf("callback: GetProviderName failed %v", err)
@ -168,16 +152,18 @@ func main() {
log.Errorf("callback: CompleteUserAuth failed %v", err) log.Errorf("callback: CompleteUserAuth failed %v", err)
return return
} }
log.Info("logged in user")
// t, _ := template.New("msg").Parse(msgTemplate)
// t.Execute(w, fmt.Sprintf("Connected with UserID '%s'", user.UserID))
w.Header().Set("Content-Type", "text/html; charset=utf-8") log.Infof("logged in user to '%s'\n", vars["provider"])
w.WriteHeader(http.StatusOK) t, _ := template.New("res").Parse(resTemplate)
result := fmt.Sprintf(`{"token":"%s", "provider":"%s"}`, user.AccessToken, user.Provider)
log.Info("details: %+v", user) data := struct {
w.Write([]byte(fmt.Sprintf(script, "success", provider, result))) Provider string
OAuthResult string
}{
Provider: fmt.Sprintf(`authorizing:%s`, provider),
OAuthResult: fmt.Sprintf(`authorization:%s:%s:{"token":"%s", "provider":"%s"}`, provider, "success", user.AccessToken, user.Provider),
}
t.Execute(w, data)
}).Methods("GET") }).Methods("GET")
// redirect to correct auth/{provider} URL if Auth request is submited with a query param '&provider=X' // redirect to correct auth/{provider} URL if Auth request is submited with a query param '&provider=X'
@ -191,7 +177,9 @@ func main() {
}).Methods("GET") }).Methods("GET")
r.HandleFunc("/auth/{provider}", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/auth/{provider}", func(w http.ResponseWriter, r *http.Request) {
log.Infof("handling auth provider request '%s'\n", r) vars := mux.Vars(r)
log.Infof("handling auth provider request '%s'\n", vars["provider"])
if gothUser, err := gothic.CompleteUserAuth(w, r); err == nil { if gothUser, err := gothic.CompleteUserAuth(w, r); err == nil {
t, _ := template.New("msg").Parse(msgTemplate) t, _ := template.New("msg").Parse(msgTemplate)
t.Execute(w, fmt.Sprintf("Connected to existing session with UserID '%s'", gothUser.UserID)) t.Execute(w, fmt.Sprintf("Connected to existing session with UserID '%s'", gothUser.UserID))
@ -201,7 +189,9 @@ func main() {
}).Methods("GET") }).Methods("GET")
r.HandleFunc("/logout/{provider}", func(w http.ResponseWriter, r *http.Request) { r.HandleFunc("/logout/{provider}", func(w http.ResponseWriter, r *http.Request) {
log.Infof("logout with '%s'\n", r) vars := mux.Vars(r)
log.Infof("logout from '%s'\n", vars["provider"])
gothic.Logout(w, r) gothic.Logout(w, r)
w.Header().Set("Location", "/") w.Header().Set("Location", "/")
w.WriteHeader(http.StatusTemporaryRedirect) w.WriteHeader(http.StatusTemporaryRedirect)