3
0

More robust external auth flow

This commit is contained in:
Denis Arh
2019-07-13 17:39:00 +02:00
parent 669a2435e4
commit 00bad0cfce
2 changed files with 74 additions and 43 deletions
+7 -1
View File
@@ -28,11 +28,17 @@ func setupGoth(eas *externalAuthSettings) {
store := sessions.NewCookieStore([]byte(eas.sessionStoreSecret))
store.MaxAge(gothMaxSessionStoreAge)
store.Options.Path = "/auth/external"
store.Options.HttpOnly = true
store.Options.Secure = eas.sessionStoreSecure
gothic.Store = store
log().Debug("registering cookie session store")
if store.Options.Secure {
log().Debug("cookie session store has 'secure' flag ON, make sure this URL is accessed via HTTPS")
}
setupGothProviders(eas)
}
+67 -42
View File
@@ -18,6 +18,7 @@ import (
"github.com/cortezaproject/corteza-server/internal/auth"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/cortezaproject/corteza-server/system/internal/service"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
@@ -29,6 +30,7 @@ type (
const (
externalAuthBaseUrl = "/auth/external"
redirCookieName = "redir"
)
func NewExternalAuth() *ExternalAuth {
@@ -43,12 +45,6 @@ func (ctrl ExternalAuth) log(ctx context.Context, fields ...zapcore.Field) *zap.
}
func (ctrl *ExternalAuth) ApiServerRoutes(r chi.Router) {
// Make sure we're backwards compatible and redirect /oidc to /auth/external/openid-connect.corteza-iam
r.Get("/oidc", func(w http.ResponseWriter, req *http.Request) {
http.Redirect(w, req, externalAuthBaseUrl+"/openid-connect.corteza-iam", http.StatusMovedPermanently)
})
// Copy provider from path (Chi URL param) to request context and return it
copyProviderToContext := func(r *http.Request) *http.Request {
return r.WithContext(context.WithValue(r.Context(), "provider", chi.URLParam(r, "provider")))
@@ -60,7 +56,7 @@ func (ctrl *ExternalAuth) ApiServerRoutes(r chi.Router) {
// Always set redir cookie, even if not requested.
// If param is empty, cookie will be removed
ctrl.setSessionCookie(w, r, "redir", r.URL.Query().Get("redir"))
ctrl.setSessionCookie(w, r, redirCookieName, r.URL.Query().Get("redir"))
// try to get the user without re-authenticating
if user, err := gothic.CompleteUserAuth(w, r); err != nil {
@@ -121,51 +117,80 @@ func (ctrl *ExternalAuth) handleSuccessfulAuth(w http.ResponseWriter, r *http.Re
svc := ctrl.auth.With(r.Context())
if u, err := svc.External(cred); err != nil {
resputil.JSON(w, err)
} else {
var (
token string
redirUrl *url.URL
c *http.Cookie
)
var (
u *types.User
err error
)
if c, err = r.Cookie("redir"); c != nil && err == nil {
if redirUrl, err = url.Parse(c.Value); err == nil {
// @todo validate origin/redir-domain
ctrl.setSessionCookie(w, r, "redir", "")
}
} else if fru := svc.FrontendRedirectURL(); fru != "" {
// Try to login/sign-up external user
if u, err = svc.External(cred); err != nil {
resputil.JSON(w, err)
return
}
var (
ctx = r.Context()
token string
redirUrl *url.URL
c *http.Cookie
)
if c, err = r.Cookie(redirCookieName); err != nil && err != http.ErrNoCookie {
ctrl.log(ctx, zap.Error(err)).Warn("error reading cookies")
}
if c != nil {
// Remove cookie
ctrl.setSessionCookie(w, r, redirCookieName, "")
redirUrl, err = url.Parse(c.Value)
if redirUrl == nil {
ctrl.log(ctx, zap.Error(err)).Warn("failed to parse URL from redir cookie")
}
}
if redirUrl == nil {
// Try with frontend redirect URL
if fru := svc.FrontendRedirectURL(); fru != "" {
redirUrl, err = url.Parse(fru)
if redirUrl == nil {
ctrl.log(ctx, zap.Error(err)).Warn("failed to parse URL from 'auth.frontend.url.redirect' settings")
}
} else {
// No info about where should we be redirected.
// Let's go directly to /auth and append the token
redirUrl = r.URL
redirUrl.RawQuery = ""
search := "/auth/"
p := strings.Index(redirUrl.Path, search)
if p > -1 {
redirUrl.Path = redirUrl.Path[0 : p+len(search)]
} else {
redirUrl.Path = "/"
}
}
}
if redirUrl != nil {
q := redirUrl.Query()
if u != nil {
// Append auth request token to the URL
// This token is used by the client and exchanged for JWT
if token, err = svc.IssueAuthRequestToken(u); err == nil {
q.Set("token", token)
}
}
if err != nil {
resputil.JSON(w, err)
return
q.Set("err", err.Error())
}
if redirUrl != nil {
q := redirUrl.Query()
if u != nil {
if token, err = svc.IssueAuthRequestToken(u); err == nil {
q.Set("token", token)
}
}
if err != nil {
q.Set("err", err.Error())
}
redirUrl.RawQuery = q.Encode()
w.Header().Set("Location", redirUrl.String())
w.WriteHeader(http.StatusSeeOther)
}
redirUrl.RawQuery = q.Encode()
w.Header().Set("Location", redirUrl.String())
w.WriteHeader(http.StatusSeeOther)
}
}