sproxy2 1.91.0 → 1.92.0
raw patch · 6 files changed
+102/−38 lines, 6 files
Files
- ChangeLog.md +13/−0
- sproxy.sql +11/−6
- sproxy.yml.example +31/−8
- sproxy2.cabal +1/−1
- src/Sproxy/Config.hs +8/−4
- src/Sproxy/Server.hs +38/−19
ChangeLog.md view
@@ -1,5 +1,18 @@ For differences with the original Sproxy scroll down. +1.92.0+======++ * Allow running in plain HTTP mode (no SSL). Useful when Sproxy is behind some+ other proxy or load-balancer. Added two more options: `ssl` (defaults to true)+ and `https_port` (defaults to like `listen`). Options `ssl_key` and `ssl_cert`+ are required only if `ssl == true`. SSL-terminations is still required at upstream+ proxies, because the cookie is set for HTTPS only.++ * Added "user" table into `sproxy.sql`. No action is required, but PostgreSQL database+ built after this file will be incompatible with Sproxy Web ( <= 0.4.1 at least).++ 1.91.0 ======
sproxy.sql view
@@ -30,6 +30,11 @@ "comment" TEXT ); +CREATE TABLE IF NOT EXISTS "user" (+ "email" TEXT NOT NULL PRIMARY KEY,+ "comment" TEXT+);+ -- | group | -- |--------------| -- | data science |@@ -40,18 +45,18 @@ CREATE TABLE IF NOT EXISTS group_member ( "group" TEXT REFERENCES "group" ("group") ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,- email TEXT NOT NULL,+ "email" TEXT REFERENCES "user" ("email") ON UPDATE CASCADE ON DELETE CASCADE NOT NULL, "comment" TEXT, PRIMARY KEY ("group", email) ); -- | group | email | -- |--------------+------------------------|--- | data science | blah@example.com |--- | data science | foo@example.com |--- | devops | devops1@example.com |--- | devops | devops2@example.com |--- | all | %@example.com |+-- | data science | blah@example.com |+-- | data science | foo@example.com |+-- | devops | devops1@example.com |+-- | devops | devops2@example.com |+-- | all | %@example.com | -- Find out which groups a user (email address) belongs to: -- SELECT "group" FROM group_member WHERE 'email.address' LIKE email
sproxy.yml.example view
@@ -10,13 +10,36 @@ # # listen: 443 -# Listen on port 80 and redirect HTTP requests to HTTPS.-# Optional. Default is true when listen == 443, otherwise false.+# Whether SSL is used on port defined by `listen`.+# You should only set it to false iff you intent to do SSL-termination+# somewhere else, e. g. at a load-balancer in a local network.+# If true, you also have to specify `ssl_key` and `ssl_cert`.+# Note that there is no way Sproxy can be usable without HTTPS/SSL at the user side,+# because Sproxy sets cookie for HTTPS only.+# Optional. Default is true.+# ssl: true++# Listen on port 80 and redirect HTTP requests to HTTPS (see `https_port`).+# Optional. Default is true when `listen` == 443, otherwise false. # # listen80: true -# Whether HTTP2 is enabled. Optional. Default is "true"+# Port used in redirection of HTTP requests to HTTPS.+# I. e., http://example.com -> https://example.com[:https_port],+# If `http_port` == 443, the port part if omitted.+# This is useful when behind a dump proxy or load-balancer, like Amazon ELB,+# (and`ssl` == false). It's unlikely that something other than 443+# is exposed to users, but if you are behind a proxy+# you can't really know the correct https port.+# Optional. Default is as `listen`. #+# Example:+# https_port: 4040+#+# https_port:++# Whether HTTP2 is enabled. Optional. Default is true.+# # http2: true # The system user Sproxy switches to if launched as root (after opening the ports).@@ -30,14 +53,14 @@ # home: "." -# File with SSL certificate. Required.+# File with SSL certificate. Required if `ssl` == true. # It can be a bundle with the server certificate coming first: # cat me-cert.pem CA-cert.pem > cert.pem # Once again: most wanted certs go first ;-) # Or you can opt in using of `ssl_cert_chain` ssl_cert: /path/cert.pem -# File with SSL key (secret!). Required.+# File with SSL key (secret!). Required if `ssl` = true. ssl_key: /path/key.pem # Chain SSL certificate files.@@ -53,8 +76,8 @@ # PostgreSQL database connection string. # Optional. If specified, sproxy will periodically pull the data from this # database into internal SQLite3 database. Define password in a file-# referenced by the PGPASSFILE environment variable. Or use the "pgpassfile" option.-# Cannot be used with the "datafile" option.+# referenced by the PGPASSFILE environment variable. Or use the `pgpassfile` option.+# Cannot be used with the `datafile` option. # Example: # database: "user=sproxy-readonly dbname=sproxy port=6001" #@@ -72,7 +95,7 @@ # Optional. If specified, Sproxy will import it on start overwriting # and existing data in the internal database. # Useful for development or some simple deployments.-# Cannot be used with the "database" option.+# Cannot be used with the `database` option. # For example see the datafile.yml.example # # datafile: /path/data.yml
sproxy2.cabal view
@@ -1,5 +1,5 @@ name: sproxy2-version: 1.91.0+version: 1.92.0 synopsis: Secure HTTP proxy for authenticating users via OAuth2 description: Sproxy is secure by default. No requests makes it to the backend
src/Sproxy/Config.hs view
@@ -17,14 +17,16 @@ data ConfigFile = ConfigFile { cfListen :: Word16+, cfSsl :: Bool , cfUser :: String , cfHome :: FilePath , cfLogLevel :: LogLevel-, cfSslCert :: FilePath-, cfSslKey :: FilePath+, cfSslCert :: Maybe FilePath+, cfSslKey :: Maybe FilePath , cfSslCertChain :: [FilePath] , cfKey :: Maybe FilePath , cfListen80 :: Maybe Bool+, cfHttpsPort :: Maybe Word16 , cfBackends :: [BackendConf] , cfOAuth2 :: HashMap Text OAuth2Conf , cfDataFile :: Maybe FilePath@@ -36,14 +38,16 @@ instance FromJSON ConfigFile where parseJSON (Object m) = ConfigFile <$> m .:? "listen" .!= 443+ <*> m .:? "ssl" .!= True <*> m .:? "user" .!= "sproxy" <*> m .:? "home" .!= "." <*> m .:? "log_level" .!= Debug- <*> m .: "ssl_cert"- <*> m .: "ssl_key"+ <*> m .:? "ssl_cert"+ <*> m .:? "ssl_key" <*> m .:? "ssl_cert_chain" .!= [] <*> m .:? "key" <*> m .:? "listen80"+ <*> m .:? "https_port" <*> m .: "backends" <*> m .: "oauth2" <*> m .:? "datafile"
src/Sproxy/Server.hs view
@@ -14,11 +14,12 @@ import Data.Yaml (decodeFileEither) import Network.HTTP.Client (Manager, ManagerSettings(..), defaultManagerSettings, newManager, socketConnection) import Network.HTTP.Client.Internal (Connection)-import Network.Socket ( Family(AF_INET, AF_UNIX), SockAddr(SockAddrInet, SockAddrUnix),+import Network.Socket ( Socket, Family(AF_INET, AF_UNIX), SockAddr(SockAddrInet, SockAddrUnix), SocketOption(ReuseAddr), SocketType(Stream), bind, close, connect, inet_addr, listen, maxListenQueue, setSocketOption, socket )+import Network.Wai (Application) import Network.Wai.Handler.WarpTLS (tlsSettingsChain, runTLSSocket)-import Network.Wai.Handler.Warp ( defaultSettings, runSettingsSocket,+import Network.Wai.Handler.Warp ( Settings, defaultSettings, runSettingsSocket, setHTTP2Disabled, setOnException ) import System.Entropy (getEntropy) import System.Environment (setEnv)@@ -37,6 +38,11 @@ import qualified Sproxy.Server.DB as DB +{- TODO:+ - Log.error && exitFailure should be replaced+ - by Log.fatal && wait for logger thread to print && exitFailure+-}+ server :: FilePath -> IO () server configFile = do cf <- readConfigFile configFile@@ -75,12 +81,11 @@ (\f -> Log.info ("reading key from " ++ f) >> BS.readFile f) (cfKey cf) - case maybe80 of- Nothing -> return ()- Just sock80 -> do- Log.info "listening on port 80 (HTTP redirect)"- listen sock80 maxListenQueue- void . forkIO $ runSettingsSocket defaultSettings sock80 (redirect $ cfListen cf)+ let+ settings =+ (if cfHTTP2 cf then id else setHTTP2Disabled) $+ setOnException (\_ _ -> return ())+ defaultSettings oauth2clients <- HM.fromList <$> mapM newOAuth2Client (HM.toList (cfOAuth2 cf)) @@ -90,21 +95,22 @@ return (compile $ beName be, be, m) ) $ cfBackends cf - let- settings =- (if cfHTTP2 cf then id else setHTTP2Disabled) $- setOnException (\_ _ -> return ())- defaultSettings + warpServer <- newServer cf++ case maybe80 of+ Nothing -> return ()+ Just sock80 -> do+ let httpsPort = fromMaybe (cfListen cf) (cfHttpsPort cf)+ Log.info "listening on port 80 (HTTP redirect)"+ listen sock80 maxListenQueue+ void . forkIO $ runSettingsSocket settings sock80 (redirect httpsPort)+ -- XXX 2048 is from bindPortTCP from streaming-commons used internally by runTLS. -- XXX Since we don't call runTLS, we listen socket here with the same options.- Log.info $ "listening on port " ++ show (cfListen cf) ++ " (HTTPS)"+ Log.info $ "proxy listening on port " ++ show (cfListen cf) listen sock (max 2048 maxListenQueue)- runTLSSocket- (tlsSettingsChain (cfSslCert cf) (cfSslCertChain cf) (cfSslKey cf))- settings- sock- (sproxy key db oauth2clients backends)+ warpServer settings sock (sproxy key db oauth2clients backends) newDataSource :: ConfigFile -> IO (Maybe DB.DataSource)@@ -165,6 +171,19 @@ managerRawConnection = return $ \_ _ _ -> openConn , managerConnCount = beConnCount be }+++newServer :: ConfigFile -> IO (Settings -> Socket -> Application -> IO ())+newServer cf+ | cfSsl cf =+ case (cfSslKey cf, cfSslCert cf) of+ (Just k, Just c) ->+ return $ runTLSSocket (tlsSettingsChain c (cfSslCertChain cf) k)+ _ -> do Log.error "missings SSL certificate"+ exitFailure+ | otherwise = do+ Log.warn "not using SSL!"+ return runSettingsSocket openUnixSocketConnection :: FilePath -> IO Connection