authelia/internal/server/server.go
Clément Michaud b12d9d405f
[FEATURE] Add Content-Security-Policy meta to login portal. (#822)
CSP is used to avoid some attacks where the hacker tries to execute
untrusted code in the browser.

The policy is to use assets hosted on the the original website and in order to make CSP work with material UI, a nonce is generated at each request of index.html and injected in the template as well as provided in the Content-Security-Policy header (https://material-ui.com/styles/advanced/#how-does-one-implement-csp)

Fix #815
2020-04-21 10:23:28 +10:00

132 lines
5.2 KiB
Go

package server
import (
"fmt"
"os"
"path"
duoapi "github.com/duosecurity/duo_api_golang"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/expvarhandler"
"github.com/valyala/fasthttp/pprofhandler"
"github.com/authelia/authelia/internal/configuration/schema"
"github.com/authelia/authelia/internal/duo"
"github.com/authelia/authelia/internal/handlers"
"github.com/authelia/authelia/internal/logging"
"github.com/authelia/authelia/internal/middlewares"
)
// StartServer start Authelia server with the given configuration and providers.
func StartServer(configuration schema.Configuration, providers middlewares.Providers) {
autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers)
publicDir := os.Getenv("PUBLIC_DIR")
if publicDir == "" {
publicDir = "./public_html"
}
logging.Logger().Infof("Selected public_html directory is %s", publicDir)
router := router.New()
router.GET("/", ServeIndex(publicDir))
router.ServeFiles("/static/{filepath:*}", publicDir+"/static")
router.GET("/api/state", autheliaMiddleware(handlers.StateGet))
router.GET("/api/configuration", autheliaMiddleware(handlers.ConfigurationGet))
router.GET("/api/configuration/extended", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.ExtendedConfigurationGet)))
router.GET("/api/verify", autheliaMiddleware(handlers.VerifyGet))
router.HEAD("/api/verify", autheliaMiddleware(handlers.VerifyGet))
router.POST("/api/firstfactor", autheliaMiddleware(handlers.FirstFactorPost))
router.POST("/api/logout", autheliaMiddleware(handlers.LogoutPost))
// only register endpoints if forgot password is not disabled
if !configuration.AuthenticationBackend.DisableResetPassword {
// Password reset related endpoints.
router.POST("/api/reset-password/identity/start", autheliaMiddleware(
handlers.ResetPasswordIdentityStart))
router.POST("/api/reset-password/identity/finish", autheliaMiddleware(
handlers.ResetPasswordIdentityFinish))
router.POST("/api/reset-password", autheliaMiddleware(
handlers.ResetPasswordPost))
}
// Information about the user
router.GET("/api/user/info", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.UserInfoGet)))
router.POST("/api/user/info/2fa_method", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.MethodPreferencePost)))
// TOTP related endpoints
router.POST("/api/secondfactor/totp/identity/start", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityStart)))
router.POST("/api/secondfactor/totp/identity/finish", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityFinish)))
router.POST("/api/secondfactor/totp", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPPost(&handlers.TOTPVerifierImpl{
Period: uint(configuration.TOTP.Period),
Skew: uint(*configuration.TOTP.Skew),
}))))
// U2F related endpoints
router.POST("/api/secondfactor/u2f/identity/start", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityStart)))
router.POST("/api/secondfactor/u2f/identity/finish", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityFinish)))
router.POST("/api/secondfactor/u2f/register", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorU2FRegister)))
router.POST("/api/secondfactor/u2f/sign_request", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignGet)))
router.POST("/api/secondfactor/u2f/sign", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignPost(&handlers.U2FVerifierImpl{}))))
// Configure DUO api endpoint only if configuration exists
if configuration.DuoAPI != nil {
var duoAPI duo.API
if os.Getenv("ENVIRONMENT") == "dev" {
duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi(
configuration.DuoAPI.IntegrationKey,
configuration.DuoAPI.SecretKey,
configuration.DuoAPI.Hostname, "", duoapi.SetInsecure()))
} else {
duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi(
configuration.DuoAPI.IntegrationKey,
configuration.DuoAPI.SecretKey,
configuration.DuoAPI.Hostname, ""))
}
router.POST("/api/secondfactor/duo", autheliaMiddleware(
middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI))))
}
// If trace is set, enable pprofhandler and expvarhandler
if configuration.LogLevel == "trace" {
router.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler)
router.GET("/debug/vars", expvarhandler.ExpvarHandler)
}
router.NotFound = func(ctx *fasthttp.RequestCtx) {
ctx.SendFile(path.Join(publicDir, "index.html"))
}
server := &fasthttp.Server{
Handler: middlewares.LogRequestMiddleware(router.Handler),
}
addrPattern := fmt.Sprintf("%s:%d", configuration.Host, configuration.Port)
if configuration.TLSCert != "" && configuration.TLSKey != "" {
logging.Logger().Infof("Authelia is listening for TLS connections on %s", addrPattern)
logging.Logger().Fatal(server.ListenAndServeTLS(addrPattern, configuration.TLSCert, configuration.TLSKey))
} else {
logging.Logger().Infof("Authelia is listening for non-TLS connections on %s", addrPattern)
logging.Logger().Fatal(server.ListenAndServe(addrPattern))
}
}