From 6174987c6aea7b9531161f1b1f4a80de79ff0d77 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:24:04 -0700 Subject: [PATCH 01/16] Adds generic oAuth bool & name string to login view. Signed-off-by: prichier --- account.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/account.go b/account.go index 56a4f84..a93f268 100644 --- a/account.go +++ b/account.go @@ -66,7 +66,7 @@ func NewUserPage(app *App, r *http.Request, u *User, title string, flashes []str } func canUserInvite(cfg *config.Config, isAdmin bool) bool { - return cfg.App.UserInvites != "" && + return cfg.App.UserInvites != "" && (isAdmin || cfg.App.UserInvites != "admin") } @@ -299,14 +299,16 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { p := &struct { page.StaticPage - To string - Message template.HTML - Flashes []template.HTML - LoginUsername string - OauthSlack bool - OauthWriteAs bool - OauthGitlab bool - GitlabDisplayName string + To string + Message template.HTML + Flashes []template.HTML + LoginUsername string + OauthSlack bool + OauthWriteAs bool + OauthGitlab bool + OauthGeneric bool + OauthGenericDisplayName string + GitlabDisplayName string }{ pageForReq(app, r), r.FormValue("to"), @@ -316,6 +318,8 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { app.Config().SlackOauth.ClientID != "", app.Config().WriteAsOauth.ClientID != "", app.Config().GitlabOauth.ClientID != "", + app.Config().GenericOauth.ClientID != "", + config.OrDefaultString(app.Config().GenericOauth.DisplayName, oAuthGenericDisplayName), config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), } From 89f7946cb05725a158b8e1d84dc90058a7ece8fa Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:28:19 -0700 Subject: [PATCH 02/16] Add config/ini structures for generic oauth Signed-off-by: prichier --- config/config.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/config.go b/config/config.go index 520dd59..f2646d2 100644 --- a/config/config.go +++ b/config/config.go @@ -86,6 +86,18 @@ type ( CallbackProxyAPI string `ini:"callback_proxy_api"` } + GenericOauthCfg struct { + ClientID string `ini:"client_id"` + ClientSecret string `ini:"client_secret"` + Host string `ini:"host"` + DisplayName string `ini:"display_name"` + CallbackProxy string `ini:"callback_proxy"` + CallbackProxyAPI string `ini:"callback_proxy_api"` + TokenEndpoint string `ini:"token_endpoint"` + InspectEndpoint string `ini:"inspect_endpoint"` + AuthEndpoint string `ini:"auth_endpoint"` + } + // AppCfg holds values that affect how the application functions AppCfg struct { SiteName string `ini:"site_name"` @@ -138,6 +150,7 @@ type ( SlackOauth SlackOauthCfg `ini:"oauth.slack"` WriteAsOauth WriteAsOauthCfg `ini:"oauth.writeas"` GitlabOauth GitlabOauthCfg `ini:"oauth.gitlab"` + GenericOauth GenericOauthCfg `ini:"oauth.generic"` } ) From ee1ca48800d5d0097272352a94bb6fff1916730c Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:40:49 -0700 Subject: [PATCH 03/16] Add generic oauth client Signed-off-by: prichier --- oauth.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/oauth.go b/oauth.go index b5c88aa..fd3ccb2 100644 --- a/oauth.go +++ b/oauth.go @@ -235,6 +235,34 @@ func configureGitlabOauth(parentHandler *Handler, r *mux.Router, app *App) { } } +func configureGenericOauth(parentHandler *Handler, r *mux.Router, app *App) { + if app.Config().GenericOauth.ClientID != "" { + callbackLocation := app.Config().App.Host + "/oauth/callback/generic" + + var callbackProxy *callbackProxyClient = nil + if app.Config().GenericOauth.CallbackProxy != "" { + callbackProxy = &callbackProxyClient { + server: app.Config().GenericOauth.CallbackProxyAPI, + callbackLocation: app.Config().App.Host + "/oauth/callback/generic", + httpClient: config.DefaultHTTPClient(), + } + callbackLocation = app.Config().GenericOauth.CallbackProxy + } + + address := app.Config().GenericOauth.Host + oauthClient := genericOauthClient{ + ClientID: app.Config().GenericOauth.ClientID, + ClientSecret: app.Config().GenericOauth.ClientSecret, + ExchangeLocation: app.Config().GenericOauth.TokenEndpoint, + InspectLocation: app.Config().GenericOauth.InspectEndpoint, + AuthLocation: app.Config().GenericOauth.AuthEndpoint, + HttpClient: config.DefaultHTTPClient(), + CallbackLocation: callbackLocation, + } + configureOauthRoutes(parentHandler, r, app, oauthClient, callbackProxy) + } +} + func configureOauthRoutes(parentHandler *Handler, r *mux.Router, app *App, oauthClient oauthClient, callbackProxy *callbackProxyClient) { handler := &oauthHandler{ Config: app.Config(), From 75ca5cd4179b9f2fc3122f726fcb06fb883ab3c3 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:44:04 -0700 Subject: [PATCH 04/16] Add generic oauth module Signed-off-by: prichier --- oauth_generic.go | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 oauth_generic.go diff --git a/oauth_generic.go b/oauth_generic.go new file mode 100644 index 0000000..6c8c15d --- /dev/null +++ b/oauth_generic.go @@ -0,0 +1,114 @@ +package writefreely + +import ( + "context" + "errors" + "net/http" + "net/url" + "strings" +) + +type genericOauthClient struct { + ClientID string + ClientSecret string + AuthLocation string + ExchangeLocation string + InspectLocation string + CallbackLocation string + HttpClient HttpClient +} + +var _ oauthClient = genericOauthClient{} + +const ( + genericOauthDisplayName = "oAuth" +) + +func (c genericOauthClient) GetProvider() string { + return "generic" +} + +func (c genericOauthClient) GetClientID() string { + return c.ClientID +} + +func (c genericOauthClient) GetCallbackLocation() string { + return c.CallbackLocation +} + +func (c genericOauthClient) buildLoginURL(state string) (string, error) { + u, err := url.Parse(c.AuthLocation) + if err != nil { + return "", err + } + q := u.Query() + q.Set("client_id", c.ClientID) + q.Set("redirect_uri", c.CallbackLocation) + q.Set("response_type", "code") + q.Set("state", state) + q.Set("scope", "read_user") + u.RawQuery = q.Encode() + return u.String(), nil +} + +func (c genericOauthClient) exchangeOauthCode(ctx context.Context, code string) (*TokenResponse, error) { + form := url.Values{} + form.Add("grant_type", "authorization_code") + form.Add("redirect_uri", c.CallbackLocation) + form.Add("scope", "read_user") + form.Add("code", code) + req, err := http.NewRequest("POST", c.ExchangeLocation, strings.NewReader(form.Encode())) + if err != nil { + return nil, err + } + req.WithContext(ctx) + req.Header.Set("User-Agent", "writefreely") + req.Header.Set("Accept", "application/json") + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.SetBasicAuth(c.ClientID, c.ClientSecret) + + resp, err := c.HttpClient.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, errors.New("unable to exchange code for access token") + } + + var tokenResponse TokenResponse + if err := limitedJsonUnmarshal(resp.Body, tokenRequestMaxLen, &tokenResponse); err != nil { + return nil, err + } + if tokenResponse.Error != "" { + return nil, errors.New(tokenResponse.Error) + } + return &tokenResponse, nil +} + +func (c genericOauthClient) inspectOauthAccessToken(ctx context.Context, accessToken string) (*InspectResponse, error) { + req, err := http.NewRequest("GET", c.InspectLocation, nil) + if err != nil { + return nil, err + } + req.WithContext(ctx) + req.Header.Set("User-Agent", "writefreely") + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", "Bearer "+accessToken) + + resp, err := c.HttpClient.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, errors.New("unable to inspect access token") + } + + var inspectResponse InspectResponse + if err := limitedJsonUnmarshal(resp.Body, infoRequestMaxLen, &inspectResponse); err != nil { + return nil, err + } + if inspectResponse.Error != "" { + return nil, errors.New(inspectResponse.Error) + } + return &inspectResponse, nil +} From cfd216544208a03d54aec72a0694dcc863213ea9 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:46:55 -0700 Subject: [PATCH 05/16] Add HTML for generic oauth login button Signed-off-by: prichier --- pages/login.tmpl | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pages/login.tmpl b/pages/login.tmpl index 5a338a4..ed5b1cf 100644 --- a/pages/login.tmpl +++ b/pages/login.tmpl @@ -3,6 +3,39 @@ {{end}} {{define "content"}} From badaffcd5cfcccf6b028cd3c07d5b612923a7f84 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 21:49:44 -0700 Subject: [PATCH 06/16] Add generic oauth to routes Signed-off-by: prichier --- routes.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routes.go b/routes.go index b34bd3d..e246184 100644 --- a/routes.go +++ b/routes.go @@ -76,6 +76,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { configureSlackOauth(handler, write, apper.App()) configureWriteAsOauth(handler, write, apper.App()) configureGitlabOauth(handler, write, apper.App()) + configureGenericOauth(handler, write, apper.App()) // Set up dyamic page handlers // Handle auth From 630ac1f7c021dd5cc32542c430a090a9442cbbe8 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 22:13:38 -0700 Subject: [PATCH 07/16] Typo fix Signed-off-by: prichier --- account.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account.go b/account.go index a93f268..81365a3 100644 --- a/account.go +++ b/account.go @@ -319,7 +319,7 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { app.Config().WriteAsOauth.ClientID != "", app.Config().GitlabOauth.ClientID != "", app.Config().GenericOauth.ClientID != "", - config.OrDefaultString(app.Config().GenericOauth.DisplayName, oAuthGenericDisplayName), + config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), } From 7b71d455a80e93a7876f3cc6cb33b775cf170f87 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 22:18:52 -0700 Subject: [PATCH 08/16] Apply go fmt Signed-off-by: prichier --- account.go | 10 +++++----- oauth.go | 50 ++++++++++++++++++++++++------------------------ oauth_generic.go | 2 +- routes.go | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/account.go b/account.go index 81365a3..274e71a 100644 --- a/account.go +++ b/account.go @@ -66,7 +66,7 @@ func NewUserPage(app *App, r *http.Request, u *User, title string, flashes []str } func canUserInvite(cfg *config.Config, isAdmin bool) bool { - return cfg.App.UserInvites != "" && + return cfg.App.UserInvites != "" && (isAdmin || cfg.App.UserInvites != "admin") } @@ -306,8 +306,8 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { OauthSlack bool OauthWriteAs bool OauthGitlab bool - OauthGeneric bool - OauthGenericDisplayName string + OauthGeneric bool + OauthGenericDisplayName string GitlabDisplayName string }{ pageForReq(app, r), @@ -318,8 +318,8 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { app.Config().SlackOauth.ClientID != "", app.Config().WriteAsOauth.ClientID != "", app.Config().GitlabOauth.ClientID != "", - app.Config().GenericOauth.ClientID != "", - config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), + app.Config().GenericOauth.ClientID != "", + config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), } diff --git a/oauth.go b/oauth.go index fd3ccb2..4c1cb86 100644 --- a/oauth.go +++ b/oauth.go @@ -236,31 +236,31 @@ func configureGitlabOauth(parentHandler *Handler, r *mux.Router, app *App) { } func configureGenericOauth(parentHandler *Handler, r *mux.Router, app *App) { - if app.Config().GenericOauth.ClientID != "" { - callbackLocation := app.Config().App.Host + "/oauth/callback/generic" - - var callbackProxy *callbackProxyClient = nil - if app.Config().GenericOauth.CallbackProxy != "" { - callbackProxy = &callbackProxyClient { - server: app.Config().GenericOauth.CallbackProxyAPI, - callbackLocation: app.Config().App.Host + "/oauth/callback/generic", - httpClient: config.DefaultHTTPClient(), - } - callbackLocation = app.Config().GenericOauth.CallbackProxy - } - - address := app.Config().GenericOauth.Host - oauthClient := genericOauthClient{ - ClientID: app.Config().GenericOauth.ClientID, - ClientSecret: app.Config().GenericOauth.ClientSecret, - ExchangeLocation: app.Config().GenericOauth.TokenEndpoint, - InspectLocation: app.Config().GenericOauth.InspectEndpoint, - AuthLocation: app.Config().GenericOauth.AuthEndpoint, - HttpClient: config.DefaultHTTPClient(), - CallbackLocation: callbackLocation, - } - configureOauthRoutes(parentHandler, r, app, oauthClient, callbackProxy) - } + if app.Config().GenericOauth.ClientID != "" { + callbackLocation := app.Config().App.Host + "/oauth/callback/generic" + + var callbackProxy *callbackProxyClient = nil + if app.Config().GenericOauth.CallbackProxy != "" { + callbackProxy = &callbackProxyClient{ + server: app.Config().GenericOauth.CallbackProxyAPI, + callbackLocation: app.Config().App.Host + "/oauth/callback/generic", + httpClient: config.DefaultHTTPClient(), + } + callbackLocation = app.Config().GenericOauth.CallbackProxy + } + + address := app.Config().GenericOauth.Host + oauthClient := genericOauthClient{ + ClientID: app.Config().GenericOauth.ClientID, + ClientSecret: app.Config().GenericOauth.ClientSecret, + ExchangeLocation: app.Config().GenericOauth.TokenEndpoint, + InspectLocation: app.Config().GenericOauth.InspectEndpoint, + AuthLocation: app.Config().GenericOauth.AuthEndpoint, + HttpClient: config.DefaultHTTPClient(), + CallbackLocation: callbackLocation, + } + configureOauthRoutes(parentHandler, r, app, oauthClient, callbackProxy) + } } func configureOauthRoutes(parentHandler *Handler, r *mux.Router, app *App, oauthClient oauthClient, callbackProxy *callbackProxyClient) { diff --git a/oauth_generic.go b/oauth_generic.go index 6c8c15d..4a706a4 100644 --- a/oauth_generic.go +++ b/oauth_generic.go @@ -21,7 +21,7 @@ type genericOauthClient struct { var _ oauthClient = genericOauthClient{} const ( - genericOauthDisplayName = "oAuth" + genericOauthDisplayName = "oAuth" ) func (c genericOauthClient) GetProvider() string { diff --git a/routes.go b/routes.go index e246184..43f511b 100644 --- a/routes.go +++ b/routes.go @@ -76,7 +76,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { configureSlackOauth(handler, write, apper.App()) configureWriteAsOauth(handler, write, apper.App()) configureGitlabOauth(handler, write, apper.App()) - configureGenericOauth(handler, write, apper.App()) + configureGenericOauth(handler, write, apper.App()) // Set up dyamic page handlers // Handle auth From 211d4410906e5b7fe4e7cc560cc97931ae3b6502 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Fri, 27 Mar 2020 22:21:24 -0700 Subject: [PATCH 09/16] Fix capitalisation of OAuth in display name Signed-off-by: prichier --- oauth_generic.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth_generic.go b/oauth_generic.go index 4a706a4..42c84b0 100644 --- a/oauth_generic.go +++ b/oauth_generic.go @@ -21,7 +21,7 @@ type genericOauthClient struct { var _ oauthClient = genericOauthClient{} const ( - genericOauthDisplayName = "oAuth" + genericOauthDisplayName = "OAuth" ) func (c genericOauthClient) GetProvider() string { From 92d822b5c6e71d6c12696bab4a53655a3f71aa13 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Thu, 2 Apr 2020 17:02:07 -0700 Subject: [PATCH 10/16] Remove redundant variable Signed-off-by: prichier --- oauth.go | 1 - 1 file changed, 1 deletion(-) diff --git a/oauth.go b/oauth.go index 4c1cb86..ebf79dc 100644 --- a/oauth.go +++ b/oauth.go @@ -249,7 +249,6 @@ func configureGenericOauth(parentHandler *Handler, r *mux.Router, app *App) { callbackLocation = app.Config().GenericOauth.CallbackProxy } - address := app.Config().GenericOauth.Host oauthClient := genericOauthClient{ ClientID: app.Config().GenericOauth.ClientID, ClientSecret: app.Config().GenericOauth.ClientSecret, From 405a2602ce4e4c779298def8fce39b8faff287ef Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Thu, 2 Apr 2020 21:40:37 -0700 Subject: [PATCH 11/16] Fix endpoint URI generation Signed-off-by: prichier --- oauth.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oauth.go b/oauth.go index ebf79dc..bb0de3e 100644 --- a/oauth.go +++ b/oauth.go @@ -252,9 +252,9 @@ func configureGenericOauth(parentHandler *Handler, r *mux.Router, app *App) { oauthClient := genericOauthClient{ ClientID: app.Config().GenericOauth.ClientID, ClientSecret: app.Config().GenericOauth.ClientSecret, - ExchangeLocation: app.Config().GenericOauth.TokenEndpoint, - InspectLocation: app.Config().GenericOauth.InspectEndpoint, - AuthLocation: app.Config().GenericOauth.AuthEndpoint, + ExchangeLocation: app.Config().GenericOauth.Host + app.Config().GenericOauth.TokenEndpoint, + InspectLocation: app.Config().GenericOauth.Host + app.Config().GenericOauth.InspectEndpoint, + AuthLocation: app.Config().GenericOauth.Host + app.Config().GenericOauth.AuthEndpoint, HttpClient: config.DefaultHTTPClient(), CallbackLocation: callbackLocation, } From cd01a4459d8598e0d1b7ff33b7f3b83641d5ef86 Mon Sep 17 00:00:00 2001 From: Keturah Dola-Borg Date: Thu, 2 Apr 2020 21:40:52 -0700 Subject: [PATCH 12/16] Fix login page variable name Signed-off-by: prichier --- pages/login.tmpl | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/pages/login.tmpl b/pages/login.tmpl index ed5b1cf..88a7b2b 100644 --- a/pages/login.tmpl +++ b/pages/login.tmpl @@ -3,38 +3,9 @@ {{end}} @@ -46,7 +17,7 @@ hr.short { {{range .Flashes}}
  • {{.}}
  • {{end}} {{end}} - {{ if or .OauthSlack .OauthWriteAs .OauthGitlab }} + {{ if or .OauthSlack .OauthWriteAs .OauthGitlab .OauthGeneric }}
    {{ if .OauthSlack }} Sign in with Slack @@ -57,6 +28,9 @@ hr.short { {{ if .OauthGitlab }} Sign in with {{.GitlabDisplayName}} {{ end }} + {{ if .OauthGeneric }} + Sign in with {{ .OauthGenericDisplayName }} + {{ end }}
    From fe7ff38bd8990a7125777281aedb5127689d98d0 Mon Sep 17 00:00:00 2001 From: prichier Date: Sun, 31 May 2020 04:09:14 +0200 Subject: [PATCH 13/16] Manage generic Oauth buttons on Account Settings Add generic Oauth allow_logout option --- account.go | 55 +++++++++++++++++++++--------------- config/config.go | 25 ++++++++-------- database.go | 5 +++- templates/user/settings.tmpl | 21 ++++++++++++-- 4 files changed, 67 insertions(+), 39 deletions(-) diff --git a/account.go b/account.go index 274e71a..e2949c0 100644 --- a/account.go +++ b/account.go @@ -1049,13 +1049,14 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err enableOauthSlack := app.Config().SlackOauth.ClientID != "" enableOauthWriteAs := app.Config().WriteAsOauth.ClientID != "" enableOauthGitLab := app.Config().GitlabOauth.ClientID != "" + enableOauthGeneric := app.Config().GenericOauth.ClientID != "" oauthAccounts, err := app.db.GetOauthAccounts(r.Context(), u.ID) if err != nil { log.Error("Unable to get oauth accounts for settings: %s", err) return impart.HTTPError{http.StatusInternalServerError, "Unable to retrieve user data. The humans have been alerted."} } - for _, oauthAccount := range oauthAccounts { + for idx, oauthAccount := range oauthAccounts { switch oauthAccount.Provider { case "slack": enableOauthSlack = false @@ -1063,35 +1064,43 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err enableOauthWriteAs = false case "gitlab": enableOauthGitLab = false + case "generic": + oauthAccounts[idx].DisplayName = app.Config().GenericOauth.DisplayName + oauthAccounts[idx].AllowLogout = app.Config().GenericOauth.AllowLogout + enableOauthGeneric = false } } - displayOauthSection := enableOauthSlack || enableOauthWriteAs || enableOauthGitLab || len(oauthAccounts) > 0 + displayOauthSection := enableOauthSlack || enableOauthWriteAs || enableOauthGitLab || enableOauthGeneric || len(oauthAccounts) > 0 obj := struct { *UserPage - Email string - HasPass bool - IsLogOut bool - Silenced bool - OauthSection bool - OauthAccounts []oauthAccountInfo - OauthSlack bool - OauthWriteAs bool - OauthGitLab bool - GitLabDisplayName string + Email string + HasPass bool + IsLogOut bool + Silenced bool + OauthSection bool + OauthAccounts []oauthAccountInfo + OauthSlack bool + OauthWriteAs bool + OauthGitLab bool + GitLabDisplayName string + OauthGeneric bool + OauthGenericDisplayName string }{ - UserPage: NewUserPage(app, r, u, "Account Settings", flashes), - Email: fullUser.EmailClear(app.keys), - HasPass: passIsSet, - IsLogOut: r.FormValue("logout") == "1", - Silenced: fullUser.IsSilenced(), - OauthSection: displayOauthSection, - OauthAccounts: oauthAccounts, - OauthSlack: enableOauthSlack, - OauthWriteAs: enableOauthWriteAs, - OauthGitLab: enableOauthGitLab, - GitLabDisplayName: config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), + UserPage: NewUserPage(app, r, u, "Account Settings", flashes), + Email: fullUser.EmailClear(app.keys), + HasPass: passIsSet, + IsLogOut: r.FormValue("logout") == "1", + Silenced: fullUser.IsSilenced(), + OauthSection: displayOauthSection, + OauthAccounts: oauthAccounts, + OauthSlack: enableOauthSlack, + OauthWriteAs: enableOauthWriteAs, + OauthGitLab: enableOauthGitLab, + GitLabDisplayName: config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), + OauthGeneric: enableOauthGeneric, + OauthGenericDisplayName: config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), } showUserPage(w, "settings", obj) diff --git a/config/config.go b/config/config.go index f2646d2..f2589ea 100644 --- a/config/config.go +++ b/config/config.go @@ -86,17 +86,18 @@ type ( CallbackProxyAPI string `ini:"callback_proxy_api"` } - GenericOauthCfg struct { - ClientID string `ini:"client_id"` - ClientSecret string `ini:"client_secret"` - Host string `ini:"host"` - DisplayName string `ini:"display_name"` - CallbackProxy string `ini:"callback_proxy"` - CallbackProxyAPI string `ini:"callback_proxy_api"` - TokenEndpoint string `ini:"token_endpoint"` - InspectEndpoint string `ini:"inspect_endpoint"` - AuthEndpoint string `ini:"auth_endpoint"` - } + GenericOauthCfg struct { + ClientID string `ini:"client_id"` + ClientSecret string `ini:"client_secret"` + Host string `ini:"host"` + DisplayName string `ini:"display_name"` + CallbackProxy string `ini:"callback_proxy"` + CallbackProxyAPI string `ini:"callback_proxy_api"` + TokenEndpoint string `ini:"token_endpoint"` + InspectEndpoint string `ini:"inspect_endpoint"` + AuthEndpoint string `ini:"auth_endpoint"` + AllowLogout bool `ini:"allow_logout"` + } // AppCfg holds values that affect how the application functions AppCfg struct { @@ -150,7 +151,7 @@ type ( SlackOauth SlackOauthCfg `ini:"oauth.slack"` WriteAsOauth WriteAsOauthCfg `ini:"oauth.writeas"` GitlabOauth GitlabOauthCfg `ini:"oauth.gitlab"` - GenericOauth GenericOauthCfg `ini:"oauth.generic"` + GenericOauth GenericOauthCfg `ini:"oauth.generic"` } ) diff --git a/database.go b/database.go index 0eee612..a98be71 100644 --- a/database.go +++ b/database.go @@ -14,11 +14,12 @@ import ( "context" "database/sql" "fmt" - wf_db "github.com/writeas/writefreely/db" "net/http" "strings" "time" + wf_db "github.com/writeas/writefreely/db" + "github.com/guregu/null" "github.com/guregu/null/zero" uuid "github.com/nu7hatch/gouuid" @@ -2590,6 +2591,8 @@ type oauthAccountInfo struct { Provider string ClientID string RemoteUserID string + DisplayName string + AllowLogout bool } func (db *datastore) GetOauthAccounts(ctx context.Context, userID int64) ([]oauthAccountInfo, error) { diff --git a/templates/user/settings.tmpl b/templates/user/settings.tmpl index 8ade8ad..ef9bacb 100644 --- a/templates/user/settings.tmpl +++ b/templates/user/settings.tmpl @@ -86,14 +86,22 @@ h3 { font-weight: normal; }
    - {{ $oauth_account.Provider | title }} - + {{ if $oauth_account.DisplayName}} + {{ if $oauth_account.AllowLogout}} + + {{else}} + {{.DisplayName}} + {{end}} + {{else}} + {{ $oauth_account.Provider | title }} + + {{end}}
    {{ end }}
    {{ end }} - {{ if or .OauthSlack .OauthWriteAs .OauthGitLab }} + {{ if or .OauthSlack .OauthWriteAs .OauthGitLab .OauthGeneric }}

    Link External Accounts

    Connect additional accounts to enable logging in with those providers, instead of using your username and password.

    @@ -123,6 +131,13 @@ h3 { font-weight: normal; }
    {{ end }} + {{ if .OauthGeneric }} + + {{ end }} {{ end }} {{ end }} From 724ab34006b7c9c3bd375ba33d81f81f67a90de2 Mon Sep 17 00:00:00 2001 From: prichier Date: Sat, 6 Jun 2020 23:52:26 +0200 Subject: [PATCH 14/16] Fix: option name from allow_logout to allow_disconnect --- account.go | 2 +- config/config.go | 2 +- database.go | 10 +++++----- templates/user/settings.tmpl | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/account.go b/account.go index e2949c0..4dc8ef9 100644 --- a/account.go +++ b/account.go @@ -1066,7 +1066,7 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err enableOauthGitLab = false case "generic": oauthAccounts[idx].DisplayName = app.Config().GenericOauth.DisplayName - oauthAccounts[idx].AllowLogout = app.Config().GenericOauth.AllowLogout + oauthAccounts[idx].AllowDisconnect = app.Config().GenericOauth.AllowDisconnect enableOauthGeneric = false } } diff --git a/config/config.go b/config/config.go index f2589ea..ffd171a 100644 --- a/config/config.go +++ b/config/config.go @@ -96,7 +96,7 @@ type ( TokenEndpoint string `ini:"token_endpoint"` InspectEndpoint string `ini:"inspect_endpoint"` AuthEndpoint string `ini:"auth_endpoint"` - AllowLogout bool `ini:"allow_logout"` + AllowDisconnect bool `ini:"allow_disconnect"` } // AppCfg holds values that affect how the application functions diff --git a/database.go b/database.go index a98be71..1e02010 100644 --- a/database.go +++ b/database.go @@ -2588,11 +2588,11 @@ func (db *datastore) GetIDForRemoteUser(ctx context.Context, remoteUserID, provi } type oauthAccountInfo struct { - Provider string - ClientID string - RemoteUserID string - DisplayName string - AllowLogout bool + Provider string + ClientID string + RemoteUserID string + DisplayName string + AllowDisconnect bool } func (db *datastore) GetOauthAccounts(ctx context.Context, userID int64) ([]oauthAccountInfo, error) { diff --git a/templates/user/settings.tmpl b/templates/user/settings.tmpl index ef9bacb..dbffe4d 100644 --- a/templates/user/settings.tmpl +++ b/templates/user/settings.tmpl @@ -87,7 +87,7 @@ h3 { font-weight: normal; }
    {{ if $oauth_account.DisplayName}} - {{ if $oauth_account.AllowLogout}} + {{ if $oauth_account.AllowDisconnect}} {{else}} {{.DisplayName}} From f6aa99e591f882d384140656a0a8ef35c6e1f887 Mon Sep 17 00:00:00 2001 From: prichier Date: Sun, 14 Jun 2020 00:27:25 +0200 Subject: [PATCH 15/16] Add disable_password_auth option --- account.go | 10 ++++++++++ app.go | 17 +++++++++++++++-- config/config.go | 3 +++ errors.go | 2 ++ pages/landing.tmpl | 22 ++++++++++++++++++++++ pages/login.tmpl | 26 +++++++++++++++----------- templates/user/settings.tmpl | 2 ++ 7 files changed, 69 insertions(+), 13 deletions(-) diff --git a/account.go b/account.go index 4dc8ef9..f8828d0 100644 --- a/account.go +++ b/account.go @@ -86,6 +86,11 @@ func apiSignup(app *App, w http.ResponseWriter, r *http.Request) error { } func signup(app *App, w http.ResponseWriter, r *http.Request) (*AuthUser, error) { + if app.cfg.App.DisablePasswordAuth { + err := ErrDisabledPasswordAuth + return nil, err + } + reqJSON := IsJSON(r) // Get params @@ -395,6 +400,11 @@ func login(app *App, w http.ResponseWriter, r *http.Request) error { var err error var signin userCredentials + if app.cfg.App.DisablePasswordAuth { + err := ErrDisabledPasswordAuth + return err + } + // Log in with one-time token if one is given if oneTimeToken != "" { log.Info("Login: Logging user in via token.") diff --git a/app.go b/app.go index ca92192..3c9e9d9 100644 --- a/app.go +++ b/app.go @@ -243,9 +243,22 @@ func handleViewLanding(app *App, w http.ResponseWriter, r *http.Request) error { Content template.HTML ForcedLanding bool + + OauthSlack bool + OauthWriteAs bool + OauthGitlab bool + OauthGeneric bool + OauthGenericDisplayName string + GitlabDisplayName string }{ - StaticPage: pageForReq(app, r), - ForcedLanding: forceLanding, + StaticPage: pageForReq(app, r), + ForcedLanding: forceLanding, + OauthSlack: app.Config().SlackOauth.ClientID != "", + OauthWriteAs: app.Config().WriteAsOauth.ClientID != "", + OauthGitlab: app.Config().GitlabOauth.ClientID != "", + OauthGeneric: app.Config().GenericOauth.ClientID != "", + OauthGenericDisplayName: config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), + GitlabDisplayName: config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), } banner, err := getLandingBanner(app) diff --git a/config/config.go b/config/config.go index ffd171a..7d6e840 100644 --- a/config/config.go +++ b/config/config.go @@ -141,6 +141,9 @@ type ( // Check for Updates UpdateChecks bool `ini:"update_checks"` + + // Disable password authentication if use only Oauth + DisablePasswordAuth bool `ini:"disable_password_auth"` } // Config holds the complete configuration for running a writefreely instance diff --git a/errors.go b/errors.go index 579386b..cf52df1 100644 --- a/errors.go +++ b/errors.go @@ -52,6 +52,8 @@ var ( ErrUserNotFoundEmail = impart.HTTPError{http.StatusNotFound, "Please enter your username instead of your email address."} ErrUserSilenced = impart.HTTPError{http.StatusForbidden, "Account is silenced."} + + ErrDisabledPasswordAuth = impart.HTTPError{http.StatusForbidden, "Password authentication is disabled."} ) // Post operation errors diff --git a/pages/landing.tmpl b/pages/landing.tmpl index d3867a9..f23470f 100644 --- a/pages/landing.tmpl +++ b/pages/landing.tmpl @@ -60,6 +60,11 @@ form dd { margin-top: 0; max-width: 8em; } +#generic-oauth-login { + box-sizing: border-box; + font-size: 17px; + white-space:nowrap; +} {{end}} {{define "content"}} @@ -73,6 +78,22 @@ form dd { {{ if .OpenRegistration }} + {{if .DisablePasswordAuth}} + {{ if or .OauthSlack .OauthWriteAs .OauthGitlab .OauthGeneric }} + {{ if .OauthSlack }} +
    Sign in with Slack
    + {{ end }} + {{ if .OauthWriteAs }} + + {{ end }} + {{ if .OauthGitlab }} + + {{ end }} + {{ if .OauthGeneric }} + + {{ end }} + {{ end }} + {{ else }} {{if .Flashes}}
      {{range .Flashes}}
    • {{.}}
    • {{end}}
    {{end}} @@ -101,6 +122,7 @@ form dd {
    + {{end}} {{ else }}

    Registration is currently closed.

    You can always sign up on another instance.

    diff --git a/pages/login.tmpl b/pages/login.tmpl index 88a7b2b..304df3e 100644 --- a/pages/login.tmpl +++ b/pages/login.tmpl @@ -33,12 +33,15 @@ input{margin-bottom:0.5em;} {{ end }} -
    -

    or

    -
    -
    + {{if not .DisablePasswordAuth}} +
    +

    or

    +
    +
    + {{end}} {{ end }} +{{if not .DisablePasswordAuth}}


    @@ -48,11 +51,12 @@ input{margin-bottom:0.5em;} {{if and (not .SingleUser) .OpenRegistration}}

    {{if .Message}}{{.Message}}{{else}}No account yet? Sign up to start a blog.{{end}}

    {{end}} - + + {{end}} {{end}} diff --git a/templates/user/settings.tmpl b/templates/user/settings.tmpl index dbffe4d..af25a29 100644 --- a/templates/user/settings.tmpl +++ b/templates/user/settings.tmpl @@ -41,6 +41,7 @@ h3 { font-weight: normal; }
    {{ end }} + {{if not .DisablePasswordAuth}}
    @@ -72,6 +73,7 @@ h3 { font-weight: normal; }
    + {{end}} {{ if .OauthSection }}
    From ab285644a0cc1630cede990a5cbeb14f54e3b49c Mon Sep 17 00:00:00 2001 From: prichier Date: Sun, 16 Aug 2020 20:42:55 +0200 Subject: [PATCH 16/16] Fix: signup methods mutually exclusive --- account.go | 12 ++++++------ database.go | 2 -- pages/landing.tmpl | 3 +-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/account.go b/account.go index 0a1cfb7..fbe5ad0 100644 --- a/account.go +++ b/account.go @@ -325,8 +325,8 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { app.Config().SlackOauth.ClientID != "", app.Config().WriteAsOauth.ClientID != "", app.Config().GitlabOauth.ClientID != "", - app.Config().GenericOauth.ClientID != "", config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), + app.Config().GenericOauth.ClientID != "", config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), app.Config().GiteaOauth.ClientID != "", config.OrDefaultString(app.Config().GiteaOauth.DisplayName, giteaDisplayName), @@ -1088,7 +1088,7 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err } } - displayOauthSection := enableOauthSlack || enableOauthWriteAs || enableOauthGitLab || enableOauthGeneric || enableOauthGitea || len(oauthAccounts) > 0 + displayOauthSection := enableOauthSlack || enableOauthWriteAs || enableOauthGitLab || enableOauthGeneric || enableOauthGitea || len(oauthAccounts) > 0 obj := struct { *UserPage @@ -1104,8 +1104,8 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err GitLabDisplayName string OauthGeneric bool OauthGenericDisplayName string - OauthGitea bool - GiteaDisplayName string + OauthGitea bool + GiteaDisplayName string }{ UserPage: NewUserPage(app, r, u, "Account Settings", flashes), Email: fullUser.EmailClear(app.keys), @@ -1120,8 +1120,8 @@ func viewSettings(app *App, u *User, w http.ResponseWriter, r *http.Request) err GitLabDisplayName: config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), OauthGeneric: enableOauthGeneric, OauthGenericDisplayName: config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), - OauthGitea: enableOauthGitea, - GiteaDisplayName: config.OrDefaultString(app.Config().GiteaOauth.DisplayName, giteaDisplayName), + OauthGitea: enableOauthGitea, + GiteaDisplayName: config.OrDefaultString(app.Config().GiteaOauth.DisplayName, giteaDisplayName), } showUserPage(w, "settings", obj) diff --git a/database.go b/database.go index 27f7e84..c764340 100644 --- a/database.go +++ b/database.go @@ -20,8 +20,6 @@ import ( "strings" "time" - wf_db "github.com/writeas/writefreely/db" - "github.com/guregu/null" "github.com/guregu/null/zero" uuid "github.com/nu7hatch/gouuid" diff --git a/pages/landing.tmpl b/pages/landing.tmpl index f23470f..f968404 100644 --- a/pages/landing.tmpl +++ b/pages/landing.tmpl @@ -78,7 +78,6 @@ form dd { {{ if .OpenRegistration }} - {{if .DisablePasswordAuth}} {{ if or .OauthSlack .OauthWriteAs .OauthGitlab .OauthGeneric }} {{ if .OauthSlack }}
    Sign in with Slack
    @@ -93,7 +92,7 @@ form dd { {{ end }} {{ end }} - {{ else }} + {{if not .DisablePasswordAuth}} {{if .Flashes}}
      {{range .Flashes}}
    • {{.}}
    • {{end}}
    {{end}}