Something went wrong on our end
-
Christian Pointner authoredChristian Pointner authored
auth.go 4.54 KiB
//
// tank
//
// Import and Playlist Daemon for autoradio project
//
//
// Copyright (C) 2017-2019 Christian Pointner <equinox@helsinki.at>
//
// This file is part of tank.
//
// tank is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// tank is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with tank. If not, see <http://www.gnu.org/licenses/>.
//
package auth
import (
"encoding/json"
"net/http"
"strings"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
var auth = &Auth{}
type Auth struct {
sessions *SessionManager
oidc *OIDCBackend
}
func Init(c *Config) (err error) {
if c == nil {
// authentication is disabled
return
}
if auth.sessions, err = NewSessionManager(c.Sessions); err != nil {
return
}
if c.OIDC != nil {
if auth.oidc, err = NewOIDCBackend(c.OIDC); err != nil {
return
}
}
return
}
func newSession() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
request := &NewSessionRequest{}
err := json.NewDecoder(r.Body).Decode(request)
if err != nil {
sendHTTPErrorResponse(w, http.StatusBadRequest, "Error decoding request: "+err.Error())
return
}
response := &NewSessionResponse{}
switch strings.ToLower(request.Backend) {
case "oidc":
if auth.oidc == nil {
sendHTTPErrorResponse(w, http.StatusBadRequest, "OIDC authentication is not configured")
return
}
s, err := NewOIDCSession()
if err != nil {
sendHTTPErrorResponse(w, http.StatusBadRequest, "Error creating session: "+err.Error())
return
}
response.Session = s
response.Token = s.getToken()
default:
sendHTTPErrorResponse(w, http.StatusBadRequest, "invalid authentication backend: "+request.Backend)
return
}
sendHTTPResponse(w, http.StatusOK, response)
})
}
func getSession() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s := getSessionFromBearerToken(r)
if s == nil {
sendHTTPInvalidSessionResponse(w)
return
}
if r.URL.Query().Get("wait-for-login") == "" {
sendHTTPResponse(w, http.StatusOK, s)
return
}
for {
s, sub := auth.sessions.getAndSubscribe(s.ID)
if s == nil {
sendHTTPErrorResponse(w, http.StatusNotFound, "this session does not exist")
return
}
st := s.State()
if st == SessionStateLoggedIn || st == SessionStateLoginFailed {
sendHTTPResponse(w, http.StatusOK, s)
return
}
<-sub
}
})
}
func deleteSession() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s := getSessionFromBearerToken(r)
if s == nil {
sendHTTPInvalidSessionResponse(w)
return
}
auth.sessions.remove(s.ID)
sendHTTPResponse(w, http.StatusOK, "you are now logged out")
})
}
func listBackends(w http.ResponseWriter, r *http.Request) {
backends := []AuthBackendInfo{}
if auth.oidc != nil {
backend := AuthBackendInfo{Name: "oidc"}
backend.Description = auth.oidc.String()
backends = append(backends, backend)
}
sendHTTPResponse(w, http.StatusOK, backends)
}
func disabled(w http.ResponseWriter, r *http.Request) {
sendHTTPErrorResponse(w, http.StatusBadRequest, "authentication is disabled")
}
func InstallHTTPHandler(r *mux.Router) {
if auth.sessions == nil {
r.PathPrefix("/").HandlerFunc(disabled)
return
}
sessionHandler := make(handlers.MethodHandler)
sessionHandler[http.MethodPost] = newSession()
sessionHandler[http.MethodGet] = getSession()
sessionHandler[http.MethodDelete] = deleteSession()
r.Handle("/session", sessionHandler)
r.HandleFunc("/backends", listBackends)
if auth.oidc != nil {
r.Handle("/oidc/login", auth.oidc.LoginHandler())
r.Handle("/oidc/callback", auth.oidc.CallbackHandler())
}
}
func Middleware(next http.Handler) http.Handler {
if auth.sessions == nil {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, attachSessionToRequest(r, anonAllowAll))
})
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s := getSessionFromBearerToken(r)
if s == nil || s.State() != SessionStateLoggedIn {
sendHTTPInvalidSessionResponse(w)
return
}
next.ServeHTTP(w, attachSessionToRequest(r, s))
})
}