package providerauth import ( "crypto/rand" "io" "net/http" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" "github.com/gorilla/mux" ) var instance *Handler type AuthProvider struct { ID string `json:"id"` Authenticated bool `json:"authenticated"` } func init() { var secret [16]byte if _, err := io.ReadFull(rand.Reader, secret[:]); err != nil { panic(err) } instance = &Handler{ log: util.NewLogger("providerauth"), secret: secret[:], providers: make(map[string]api.AuthProvider), states: make(map[string]stateEntry), updateC: make(chan string, 1), } } // Setup connects the redirect handler to the router and registers the callback channel. // Callback stays open: the cross-site IdP redirect carries no session cookie, the state token gates it. func Setup(router *mux.Router, paramC chan<- util.Param, authMiddleware mux.MiddlewareFunc) { gate := func(h http.HandlerFunc) http.Handler { return authMiddleware(h) } router.Methods(http.MethodGet).Path("/callback").HandlerFunc(instance.handleCallback) router.Methods(http.MethodGet).Path("/login").Handler(gate(instance.handleLogin)) router.Methods(http.MethodGet).Path("/logout").Handler(gate(instance.handleLogout)) go instance.run(paramC) } // Register registers a specific AuthProvider by name // The returned online channel is used to asynchronously update authorization status func Register(name string, handler api.AuthProvider) (chan<- bool, error) { updateC, err := instance.register(name, handler) if err != nil { return nil, err } // buffered + non-blocking send (see OAuth.setOnline): the value is only a // signal and the handler re-reads live state, so coalescing is lossless. onlineC := make(chan bool, 1) go func() { for range onlineC { updateC <- name } }() return onlineC, nil }