2019-04-25 04:52:08 +07:00
package server
import (
2020-11-06 04:57:03 +07:00
"io/ioutil"
2020-07-16 13:36:37 +07:00
"net"
2019-04-25 04:52:08 +07:00
"os"
2020-11-06 04:57:03 +07:00
"runtime"
2020-06-21 20:40:37 +07:00
"strconv"
2020-11-06 04:57:03 +07:00
"strings"
2019-04-25 04:52:08 +07:00
2020-04-05 19:37:21 +07:00
duoapi "github.com/duosecurity/duo_api_golang"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
2020-04-11 11:59:58 +07:00
"github.com/valyala/fasthttp/expvarhandler"
2020-04-28 21:07:20 +07:00
"github.com/valyala/fasthttp/fasthttpadaptor"
2020-04-11 11:59:58 +07:00
"github.com/valyala/fasthttp/pprofhandler"
2020-04-05 19:37:21 +07:00
2019-12-24 09:14:52 +07:00
"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"
2019-04-25 04:52:08 +07:00
)
// StartServer start Authelia server with the given configuration and providers.
func StartServer ( configuration schema . Configuration , providers middlewares . Providers ) {
autheliaMiddleware := middlewares . AutheliaMiddleware ( configuration , providers )
2020-04-28 21:07:20 +07:00
embeddedAssets := "/public_html"
2020-06-21 20:40:37 +07:00
rememberMe := strconv . FormatBool ( configuration . Session . RememberMeDuration != "0" )
resetPassword := strconv . FormatBool ( ! configuration . AuthenticationBackend . DisableResetPassword )
2020-05-07 18:29:12 +07:00
rootFiles := [ ] string { "favicon.ico" , "manifest.json" , "robots.txt" }
2020-05-21 09:20:55 +07:00
2020-06-21 20:40:37 +07:00
serveIndexHandler := ServeIndex ( embeddedAssets , configuration . Server . Path , rememberMe , resetPassword )
2020-05-21 09:20:55 +07:00
r := router . New ( )
2020-06-21 20:40:37 +07:00
r . GET ( "/" , serveIndexHandler )
2020-05-07 18:29:12 +07:00
for _ , f := range rootFiles {
2020-05-21 09:20:55 +07:00
r . GET ( "/" + f , fasthttpadaptor . NewFastHTTPHandler ( br . Serve ( embeddedAssets ) ) )
2020-05-07 18:29:12 +07:00
}
2020-05-21 09:20:55 +07:00
r . GET ( "/static/{filepath:*}" , fasthttpadaptor . NewFastHTTPHandler ( br . Serve ( embeddedAssets ) ) )
2019-04-25 04:52:08 +07:00
2020-05-21 09:20:55 +07:00
r . GET ( "/api/state" , autheliaMiddleware ( handlers . StateGet ) )
2019-04-25 04:52:08 +07:00
2020-06-21 20:40:37 +07:00
r . GET ( "/api/configuration" , autheliaMiddleware (
middlewares . RequireFirstFactor ( handlers . ConfigurationGet ) ) )
2019-12-07 23:40:42 +07:00
2020-05-21 09:20:55 +07:00
r . GET ( "/api/verify" , autheliaMiddleware ( handlers . VerifyGet ( configuration . AuthenticationBackend ) ) )
r . HEAD ( "/api/verify" , autheliaMiddleware ( handlers . VerifyGet ( configuration . AuthenticationBackend ) ) )
2019-04-25 04:52:08 +07:00
2020-05-21 09:20:55 +07:00
r . POST ( "/api/firstfactor" , autheliaMiddleware ( handlers . FirstFactorPost ( 1000 , true ) ) )
r . POST ( "/api/logout" , autheliaMiddleware ( handlers . LogoutPost ) )
2019-04-25 04:52:08 +07:00
2020-04-28 21:07:20 +07:00
// Only register endpoints if forgot password is not disabled.
2020-04-05 06:28:09 +07:00
if ! configuration . AuthenticationBackend . DisableResetPassword {
// Password reset related endpoints.
2020-05-21 09:20:55 +07:00
r . POST ( "/api/reset-password/identity/start" , autheliaMiddleware (
2020-04-05 06:28:09 +07:00
handlers . ResetPasswordIdentityStart ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/reset-password/identity/finish" , autheliaMiddleware (
2020-04-05 06:28:09 +07:00
handlers . ResetPasswordIdentityFinish ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/reset-password" , autheliaMiddleware (
2020-04-05 06:28:09 +07:00
handlers . ResetPasswordPost ) )
}
2019-04-25 04:52:08 +07:00
2020-04-28 21:07:20 +07:00
// Information about the user.
2020-05-21 09:20:55 +07:00
r . GET ( "/api/user/info" , autheliaMiddleware (
2019-12-07 18:18:22 +07:00
middlewares . RequireFirstFactor ( handlers . UserInfoGet ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/user/info/2fa_method" , autheliaMiddleware (
2019-12-07 18:18:22 +07:00
middlewares . RequireFirstFactor ( handlers . MethodPreferencePost ) ) )
2019-04-25 04:52:08 +07:00
2020-04-28 21:07:20 +07:00
// TOTP related endpoints.
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/totp/identity/start" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorTOTPIdentityStart ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/totp/identity/finish" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorTOTPIdentityFinish ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/totp" , autheliaMiddleware (
2020-03-25 08:48:20 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorTOTPPost ( & handlers . TOTPVerifierImpl {
Period : uint ( configuration . TOTP . Period ) ,
Skew : uint ( * configuration . TOTP . Skew ) ,
} ) ) ) )
2019-04-25 04:52:08 +07:00
2020-04-28 21:07:20 +07:00
// U2F related endpoints.
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/u2f/identity/start" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorU2FIdentityStart ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/u2f/identity/finish" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorU2FIdentityFinish ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/u2f/register" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorU2FRegister ) ) )
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/u2f/sign_request" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorU2FSignGet ) ) )
2020-02-01 19:54:50 +07:00
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/u2f/sign" , autheliaMiddleware (
2020-02-01 19:54:50 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorU2FSignPost ( & handlers . U2FVerifierImpl { } ) ) ) )
2019-04-25 04:52:08 +07:00
2020-04-28 21:07:20 +07:00
// Configure DUO api endpoint only if configuration exists.
2019-04-25 04:52:08 +07:00
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 , "" ) )
}
2020-05-21 09:20:55 +07:00
r . POST ( "/api/secondfactor/duo" , autheliaMiddleware (
2019-04-25 04:52:08 +07:00
middlewares . RequireFirstFactor ( handlers . SecondFactorDuoPost ( duoAPI ) ) ) )
}
2020-04-28 21:07:20 +07:00
// If trace is set, enable pprofhandler and expvarhandler.
2020-04-11 11:59:58 +07:00
if configuration . LogLevel == "trace" {
2020-05-21 09:20:55 +07:00
r . GET ( "/debug/pprof/{name?}" , pprofhandler . PprofHandler )
r . GET ( "/debug/vars" , expvarhandler . ExpvarHandler )
2020-04-11 11:59:58 +07:00
}
2020-06-21 20:40:37 +07:00
r . NotFound = serveIndexHandler
2020-05-21 09:20:55 +07:00
handler := middlewares . LogRequestMiddleware ( r . Handler )
if configuration . Server . Path != "" {
handler = middlewares . StripPathMiddleware ( handler )
}
2019-11-30 23:49:52 +07:00
2020-04-11 11:59:58 +07:00
server := & fasthttp . Server {
2020-04-30 10:16:41 +07:00
ErrorHandler : autheliaErrorHandler ,
2020-05-21 09:20:55 +07:00
Handler : handler ,
2020-04-30 10:16:41 +07:00
NoDefaultServerHeader : true ,
ReadBufferSize : configuration . Server . ReadBufferSize ,
WriteBufferSize : configuration . Server . WriteBufferSize ,
2020-04-11 11:59:58 +07:00
}
2020-04-30 09:03:05 +07:00
2020-07-16 13:36:37 +07:00
addrPattern := net . JoinHostPort ( configuration . Host , strconv . Itoa ( configuration . Port ) )
listener , err := net . Listen ( "tcp" , addrPattern )
if err != nil {
logging . Logger ( ) . Fatalf ( "Error initializing listener: %s" , err )
}
2019-04-25 04:52:08 +07:00
2020-11-06 04:57:03 +07:00
if configuration . AuthenticationBackend . File != nil && configuration . AuthenticationBackend . File . Password . Algorithm == "argon2id" && runtime . GOOS == "linux" {
f , err := ioutil . ReadFile ( "/sys/fs/cgroup/memory/memory.limit_in_bytes" )
if err != nil {
logging . Logger ( ) . Warnf ( "Error reading hosts memory limit: %s" , err )
} else {
m , _ := strconv . Atoi ( strings . TrimSuffix ( string ( f ) , "\n" ) )
hostMem := float64 ( m ) / 1024 / 1024 / 1024
argonMem := float64 ( configuration . AuthenticationBackend . File . Password . Memory ) / 1024
if hostMem / argonMem <= 2 {
logging . Logger ( ) . Warnf ( "Authelia's password hashing memory parameter is set to: %gGB this is %g%% of the available memory: %gGB" , argonMem , argonMem / hostMem * 100 , hostMem )
logging . Logger ( ) . Warn ( "Please read https://www.authelia.com/docs/configuration/authentication/file.html#memory and tune your deployment" )
}
}
}
2020-03-03 14:18:25 +07:00
if configuration . TLSCert != "" && configuration . TLSKey != "" {
2020-05-27 18:55:44 +07:00
logging . Logger ( ) . Infof ( "Authelia is listening for TLS connections on %s%s" , addrPattern , configuration . Server . Path )
2020-07-16 13:36:37 +07:00
logging . Logger ( ) . Fatal ( server . ServeTLS ( listener , configuration . TLSCert , configuration . TLSKey ) )
2020-03-03 14:18:25 +07:00
} else {
2020-05-27 18:55:44 +07:00
logging . Logger ( ) . Infof ( "Authelia is listening for non-TLS connections on %s%s" , addrPattern , configuration . Server . Path )
2020-07-16 13:36:37 +07:00
logging . Logger ( ) . Fatal ( server . Serve ( listener ) )
2020-03-03 14:18:25 +07:00
}
2019-04-25 04:52:08 +07:00
}