1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-10 04:17:59 +02:00

Add ability to override mail root

- Add config option for MailRoot
- Make confirm and recover use MailRoot if present, otherwise assemble
  URL like normal.
This commit is contained in:
Aaron L 2018-09-12 19:44:34 -07:00
parent 13e6714c87
commit 79d1893bdc
6 changed files with 78 additions and 7 deletions

View File

@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add Config option to defaults.HTTPRedirector to allow it to coerce redirect
response codes to http.StatusOK to help make more regular APIs.
- Add Config option for MailRoot. This is a URL that overrides the typical
URL building using Root/MountPath that recover and confirm do to enable
creating mail links to a different location than where the API is hosted.
### Changed

View File

@ -11,6 +11,7 @@ type Config struct {
Paths struct {
// Mount is the path to mount authboss's routes at (eg /auth).
Mount string
// NotAuthorized is the default URL to kick users back to when
// they attempt an action that requires them to be logged in and they're not auth'd
NotAuthorized string
@ -99,6 +100,13 @@ type Config struct {
}
Mail struct {
// RootURL is a full path to an application that is hosting a front-end
// Typically using a combination of Paths.RootURL and Paths.Mount
// MailRoot will be assembled if not set.
// Typically looks something like: https://our-front-end.com/authenication
// No trailing slash
RootURL string
// From is the email address authboss e-mails come from.
From string
// FromName is the name authboss e-mails come from.

View File

@ -143,8 +143,7 @@ var goConfirmEmail = func(c *Confirm, ctx context.Context, to, token string) {
func (c *Confirm) SendConfirmEmail(ctx context.Context, to, token string) {
logger := c.Authboss.Logger(ctx)
p := path.Join(c.Config.Paths.Mount, "confirm")
url := fmt.Sprintf("%s%s?%s=%s", c.Paths.RootURL, p, url.QueryEscape(FormValueConfirm), url.QueryEscape(token))
mailURL := c.mailURL(token)
email := authboss.Email{
To: []string{to},
@ -156,7 +155,7 @@ func (c *Confirm) SendConfirmEmail(ctx context.Context, to, token string) {
logger.Infof("sending confirm e-mail to: %s", to)
ro := authboss.EmailResponseOptions{
Data: authboss.NewHTMLData(DataConfirmURL, url),
Data: authboss.NewHTMLData(DataConfirmURL, mailURL),
HTMLTemplate: EmailConfirmHTML,
TextTemplate: EmailConfirmTxt,
}
@ -234,6 +233,17 @@ func (c *Confirm) Get(w http.ResponseWriter, r *http.Request) error {
return c.Authboss.Config.Core.Redirector.Redirect(w, r, ro)
}
func (c *Confirm) mailURL(token string) string {
query := url.Values{FormValueConfirm: []string{token}}
if len(c.Config.Mail.RootURL) != 0 {
return fmt.Sprintf("%s?%s", c.Config.Mail.RootURL+"/confirm", query.Encode())
}
p := path.Join(c.Config.Paths.Mount, "confirm")
return fmt.Sprintf("%s%s?%s", c.Config.Paths.RootURL, p, query.Encode())
}
func (c *Confirm) invalidToken(w http.ResponseWriter, r *http.Request) error {
ro := authboss.RedirectOptions{
Code: http.StatusTemporaryRedirect,

View File

@ -365,6 +365,26 @@ func TestMiddlewareDisallow(t *testing.T) {
}
}
func TestMailURL(t *testing.T) {
t.Parallel()
h := testSetup()
h.ab.Config.Paths.RootURL = "https://api.test.com:6343"
h.ab.Config.Paths.Mount = "/v1/auth"
want := "https://api.test.com:6343/v1/auth/confirm?cnf=abc"
if got := h.confirm.mailURL("abc"); got != want {
t.Error("want:", want, "got:", got)
}
h.ab.Config.Mail.RootURL = "https://test.com:3333/testauth"
want = "https://test.com:3333/testauth/confirm?cnf=abc"
if got := h.confirm.mailURL("abc"); got != want {
t.Error("want:", want, "got:", got)
}
}
func TestGenerateRecoverCreds(t *testing.T) {
t.Parallel()

View File

@ -131,9 +131,8 @@ var goRecoverEmail = func(r *Recover, ctx context.Context, to, encodedToken stri
// in an escaped URL to the templates.
func (r *Recover) SendRecoverEmail(ctx context.Context, to, encodedToken string) {
logger := r.Authboss.Logger(ctx)
p := path.Join(r.Authboss.Config.Paths.Mount, "recover/end")
query := url.Values{FormValueToken: []string{encodedToken}}
url := fmt.Sprintf("%s%s?%s", r.Authboss.Config.Paths.RootURL, p, query.Encode())
mailURL := r.mailURL(encodedToken)
email := authboss.Email{
To: []string{to},
@ -146,7 +145,7 @@ func (r *Recover) SendRecoverEmail(ctx context.Context, to, encodedToken string)
HTMLTemplate: EmailRecoverHTML,
TextTemplate: EmailRecoverTxt,
Data: authboss.HTMLData{
DataRecoverURL: url,
DataRecoverURL: mailURL,
},
}
@ -271,6 +270,17 @@ func (r *Recover) invalidToken(page string, w http.ResponseWriter, req *http.Req
return r.Authboss.Core.Responder.Respond(w, req, http.StatusOK, PageRecoverEnd, data)
}
func (r *Recover) mailURL(token string) string {
query := url.Values{FormValueToken: []string{token}}
if len(r.Config.Mail.RootURL) != 0 {
return fmt.Sprintf("%s?%s", r.Config.Mail.RootURL+"/recover/end", query.Encode())
}
p := path.Join(r.Config.Paths.Mount, "recover/end")
return fmt.Sprintf("%s%s?%s", r.Config.Paths.RootURL, p, query.Encode())
}
// GenerateRecoverCreds generates pieces needed for user recovery
// selector: hash of the first half of a 64 byte value (to be stored in the database and used in SELECT query)
// verifier: hash of the second half of a 64 byte value (to be stored in database but never used in SELECT query)

View File

@ -409,6 +409,26 @@ func TestEndPostUserNotExist(t *testing.T) {
invalidCheck(t, h, w)
}
func TestMailURL(t *testing.T) {
t.Parallel()
h := testSetup()
h.ab.Config.Paths.RootURL = "https://api.test.com:6343"
h.ab.Config.Paths.Mount = "/v1/auth"
want := "https://api.test.com:6343/v1/auth/recover/end?token=abc"
if got := h.recover.mailURL("abc"); got != want {
t.Error("want:", want, "got:", got)
}
h.ab.Config.Mail.RootURL = "https://test.com:3333/testauth"
want = "https://test.com:3333/testauth/recover/end?token=abc"
if got := h.recover.mailURL("abc"); got != want {
t.Error("want:", want, "got:", got)
}
}
func invalidCheck(t *testing.T, h *testHarness, w *httptest.ResponseRecorder) {
t.Helper()