mirror of
https://github.com/m1k1o/neko.git
synced 2026-11-03 00:11:48 -06:00
refactor(oauth): improve readability of newOAuthHandler and OAuth methods.
This commit is contained in:
@@ -32,7 +32,13 @@ func newOAuthHandler(service *oauth.Service, pathPrefix string, trustProxy, prov
|
||||
if pathPrefix == "" {
|
||||
pathPrefix = "/"
|
||||
}
|
||||
return &oauthHandler{service: service, pathPrefix: pathPrefix, trustProxy: trustProxy, providerOAuth: providerOAuth}
|
||||
|
||||
return &oauthHandler{
|
||||
service: service,
|
||||
pathPrefix: pathPrefix,
|
||||
trustProxy: trustProxy,
|
||||
providerOAuth: providerOAuth,
|
||||
}
|
||||
}
|
||||
|
||||
func (api *ApiManagerCtx) OAuthConfig(w http.ResponseWriter, r *http.Request) error {
|
||||
@@ -48,17 +54,21 @@ func (api *ApiManagerCtx) OAuthLogin(w http.ResponseWriter, r *http.Request) err
|
||||
if !api.oauth.providerOAuth || !api.oauth.service.Enabled() {
|
||||
return utils.HttpNotFound()
|
||||
}
|
||||
|
||||
if !api.sessions.CookieEnabled() {
|
||||
return utils.HttpError(http.StatusServiceUnavailable, "OAuth requires session cookies to be enabled")
|
||||
}
|
||||
|
||||
callbackURL, err := api.oauth.callbackURL(r)
|
||||
if err != nil {
|
||||
return utils.HttpInternalServerError("unable to determine OAuth callback URL").WithInternalErr(err)
|
||||
}
|
||||
|
||||
location, err := api.oauth.service.Start(r.Context(), callbackURL)
|
||||
if err != nil {
|
||||
return oauthServiceError(err, true)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, location, http.StatusFound)
|
||||
return nil
|
||||
}
|
||||
@@ -67,14 +77,17 @@ func (api *ApiManagerCtx) OAuthCallback(w http.ResponseWriter, r *http.Request)
|
||||
if !api.oauth.providerOAuth || !api.oauth.service.Enabled() {
|
||||
return utils.HttpNotFound()
|
||||
}
|
||||
|
||||
if providerError := r.URL.Query().Get("error"); providerError != "" {
|
||||
return utils.HttpUnauthorized("OAuth authorization was declined").WithInternalMsg(providerError)
|
||||
}
|
||||
|
||||
_, token, err := api.oauth.service.Complete(r.Context(), r.URL.Query().Get("state"), r.URL.Query().Get("code"))
|
||||
if err != nil {
|
||||
return oauthServiceError(err, false)
|
||||
}
|
||||
api.sessions.CookieSetToken(w, token)
|
||||
|
||||
http.Redirect(w, r, api.oauth.successRedirect(), http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
@@ -83,21 +96,27 @@ func oauthServiceError(err error, start bool) error {
|
||||
if errors.Is(err, types.ErrSessionAlreadyConnected) {
|
||||
return utils.HttpUnprocessableEntity("session already connected")
|
||||
}
|
||||
|
||||
if errors.Is(err, types.ErrSessionLoginsLocked) {
|
||||
return utils.HttpForbidden("logins are locked").WithInternalErr(err)
|
||||
}
|
||||
|
||||
if start && strings.HasPrefix(err.Error(), "issuer discovery:") {
|
||||
return utils.HttpError(http.StatusServiceUnavailable, "OAuth issuer discovery failed").WithInternalErr(err)
|
||||
}
|
||||
|
||||
if start {
|
||||
return utils.HttpError(http.StatusServiceUnavailable, err.Error()).WithInternalErr(err)
|
||||
}
|
||||
|
||||
if strings.Contains(err.Error(), "missing state or code") || strings.Contains(err.Error(), "state is invalid") {
|
||||
return utils.HttpBadRequest(err.Error()).WithInternalErr(err)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(err.Error(), "issuer discovery:") || strings.Contains(err.Error(), "not fully configured") {
|
||||
return utils.HttpError(http.StatusServiceUnavailable, "OAuth issuer discovery failed").WithInternalErr(err)
|
||||
}
|
||||
|
||||
return utils.HttpUnauthorized("OAuth authorization failed").WithInternalErr(err)
|
||||
}
|
||||
|
||||
@@ -106,6 +125,7 @@ func (handler *oauthHandler) callbackURL(r *http.Request) (string, error) {
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
host := r.Host
|
||||
if handler.trustProxy {
|
||||
if value := forwardedHeaderValue(r.Header.Get("X-Forwarded-Proto")); value != "" {
|
||||
@@ -115,22 +135,32 @@ func (handler *oauthHandler) callbackURL(r *http.Request) (string, error) {
|
||||
host = value
|
||||
}
|
||||
}
|
||||
|
||||
if host == "" || (scheme != "http" && scheme != "https") {
|
||||
return "", errors.New("request has no valid public URL")
|
||||
}
|
||||
callback := (&url.URL{Scheme: scheme, Host: host, Path: path.Join(handler.pathPrefix, "/api/oauth/callback")}).String()
|
||||
|
||||
callback := (&url.URL{
|
||||
Scheme: scheme,
|
||||
Host: host,
|
||||
Path: path.Join(handler.pathPrefix, "/api/oauth/callback"),
|
||||
}).String()
|
||||
if parsed, err := url.Parse(callback); err != nil || parsed.Host == "" {
|
||||
return "", errors.New("request has no valid public URL")
|
||||
}
|
||||
|
||||
return callback, nil
|
||||
}
|
||||
|
||||
func (handler *oauthHandler) successRedirect() string {
|
||||
redirect := handler.service.SuccessRedirect()
|
||||
if strings.HasPrefix(redirect, "/") && !strings.HasPrefix(redirect, "//") {
|
||||
return path.Join(handler.pathPrefix, redirect)
|
||||
}
|
||||
|
||||
return handler.pathPrefix
|
||||
}
|
||||
|
||||
func forwardedHeaderValue(value string) string {
|
||||
return strings.TrimSpace(strings.Split(value, ",")[0])
|
||||
}
|
||||
|
||||
@@ -43,7 +43,12 @@ func New(
|
||||
desktop: desktop,
|
||||
capture: capture,
|
||||
routers: make(map[string]func(types.Router)),
|
||||
oauth: newOAuthHandler(oauth.NewService(memberConfig.OAuth, sessions), pathPrefix, serverConfig != nil && serverConfig.Proxy, memberConfig.Provider == "oauth"),
|
||||
oauth: newOAuthHandler(
|
||||
oauth.NewService(memberConfig.OAuth, sessions),
|
||||
pathPrefix,
|
||||
serverConfig != nil && serverConfig.Proxy,
|
||||
memberConfig.Provider == "oauth",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ func (api *ApiManagerCtx) Logout(w http.ResponseWriter, r *http.Request) error {
|
||||
return utils.HttpInternalServerError().WithInternalErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
if api.sessions.CookieEnabled() {
|
||||
api.sessions.CookieClearToken(w, r)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user