packages feed

sproxy2 1.92.0 → 1.93.0

raw patch · 9 files changed

+236/−243 lines, 9 files

Files

ChangeLog.md view
@@ -1,5 +1,16 @@ For differences with the original Sproxy scroll down. +1.93.0+======++  * BREAKING: Allow `!include` in config file.+    This changes semantics of options `key` and `oauth2.<provider>.client_secret`.+    They are no longer files, but strings.  To read content from files, use+    !include.  The point of being files or read from files is to segregate secrets+    from non-sensitive easily discoverable settings.  With `!include` it is much more+    simple and flexible.++ 1.92.0 ====== 
README.md view
@@ -57,7 +57,7 @@ ------------------ Permissions are stored in internal SQLite3 database and imported from data sources, which can be a PostgreSQL database or a file.  See-[sproxy.sql](./sproxy.sql) and [datafile.yml.example](./datafile.yml.example)+[sproxy.sql](./sproxy.sql) and [datafile.example.yml](./datafile.example.yml) for details.  Do note that Sproxy2 fetches only `group_member`, `group_privilege`@@ -91,17 +91,6 @@   surprising, please see the following example:  -Keep in mind that:--- Domains are converted into lower case (coming from a data source or HTTP requests).-- Emails are converted into lower case (coming from a data source or OAuth2 providers).-- Groups are case-sensitive and treated as is.-- HTTP methods are *case-sensitive*.-- HTTP query parameters are ignored when matching a request against the rules.-- Privileges are case-sensitive and treated as is.-- SQL wildcards (`_` and `%`) are supported for emails, domains, paths.-- Privileges example ------------------ @@ -138,6 +127,17 @@ Likewise `readers` have no access to e.g. `/wiki/edit/delete_everything.php`.  +Keep in mind that:++- Domains are converted into lower case (coming from a data source or HTTP requests).+- Emails are converted into lower case (coming from a data source or OAuth2 providers).+- Groups are case-sensitive and treated as is.+- HTTP methods are *case-sensitive*.+- HTTP query parameters are ignored when matching a request against the rules.+- Privileges are case-sensitive and treated as is.+- SQL wildcards (`_` and `%`) are supported for emails, domains, paths.++ HTTP headers passed to the back-end server ------------------------------------------ @@ -198,7 +198,7 @@ =============  By default `sproxy2` will read its configuration from `sproxy.yml`.  There is-example file with documentation [sproxy.yml.example](sproxy.yml.example). You+example file with documentation [sproxy.example.yml](sproxy.example.yml). You can specify a custom path with:  ```
+ datafile.example.yml view
@@ -0,0 +1,29 @@+group_member:+  - group: "devops"+    email: "%"++  - group: "foo"+    email: "%"+++group_privilege:+  - group: "foo"+    domain: "example.com"+    privilege: "full"++  - group: "devops"+    domain: "example.com"+    privilege: "full"+++privilege_rule:+  - domain: "example.com"+    privilege: "full"+    path: "%"+    method: "GET"++  - domain: "example.com"+    privilege: "full"+    path: "%"+    method: "POST"+
− datafile.yml.example
@@ -1,34 +0,0 @@---- # Data file. Don't remove this line. This is YAML: https://en.wikipedia.org/wiki/YAML--group_member:-  - group: "devops"-    email: "%"--  - group: "foo"-    email: "%"---group_privilege:-  - group: "foo"-    domain: "example.com"-    privilege: "full"--  - group: "devops"-    domain: "example.com"-    privilege: "full"---privilege_rule:-  - domain: "example.com"-    privilege: "full"-    path: "%"-    method: "GET"--  - domain: "example.com"-    privilege: "full"-    path: "%"-    method: "POST"---... # End of data file. Don't remove this line. This is YAML: https://en.wikipedia.org/wiki/YAML-
+ sproxy.example.yml view
@@ -0,0 +1,172 @@+# NOTE: You can use the !include directive to import parts of this file.++# Logging level: debug, info, warn, error.+# Optional. Default is debug.+#+# log_level: debug++# The port Sproxy listens on (HTTPS).+# Optional. Default is 443.+#+# listen: 443++# 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++# 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 dumb 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).+# Optional. Default is sproxy.+#+# user: sproxy++# Home directory for various files including SQLite3 authorization database.+# Optional. Default is current directory.+#+# home: "."+++# 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 if `ssl` = true.+ssl_key: /path/key.pem++# Chain SSL certificate files.+# Optional. Default is an empty list+# Example:+# ssl_cert_chain:+#   - /path/foo.pem+#   - /path/bar.pem+#+# ssl_cert_chain: []+++# 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.+# Example:+# database: "user=sproxy-readonly dbname=sproxy port=6001"+#+# database:++# PostgreSQL password file.+# Optional. If specified, sproxy will set PGPASSFILE environment variable pointing to this file+# Example:+# pgpassfile: /run/keys/sproxy.pgpass+#+# pgpassfile:+++# YAML file used to fill internal SQLite3 database.+# 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.+# For example see the datafile.yml.example+#+# datafile: /path/data.yml+++# Arbitrary string used to sign sproxy cookie and other things (secret!).+# Optional. If not specified, a random key is generated on startup, and+# as a consequence, restaring sproxy will invalidate existing user sessions.+# This option could be useful for load-balancing with multiple sproxy instances,+# when all instances must understand cookies created by each other.+# This should not be very large, a few random bytes are fine.+# +# key: !include /run/keys/sproxy.secret+++# Credentials for supported OAuth2 providers.+# Currently supported: "google", "linkedin"+# At least one provider is required.+# Attributes:+#   client_id     - OAuth2 client ID.+#   client_secret - OAuth2 client secret.+#+# Example:+# oauth2:+#   google:+#     client_id: "XXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.apps.googleusercontent.com"+#     client_secret: !include /run/keys/XXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.apps.googleusercontent.com+#+#   linkedin:+#     client_id: "xxxxxxxxxxxxxx"+#     client_secret: !include "/run/keys/xxxxxxxxxxxxxx"+#+#+# oauth2:+#   google:+#     client_id:+#     client_secret:+++# Backend servers. At least one is required.+# NOTE: backends at TCP port are not secure, even on localhost,+# because any local user can connect to the backend bypassing sproxy+# authentication and authorization.+#+# It is recommended to communicate with backends via unix sockets only.+# Unix sockets should be secured with proper unix file permissions.+#+# Backend attributes:+#   name      - the host name as in the Host HTTP header.+#               May include wildcards * and ?. The first matching+#               backend will be used. Examples: "*.example.com", "wiki.corp.com".+#               Optional. Default is "*". Note, that the name must include+#               port number if non-standard.+#   address   - backend IP address. Optional. Default is 127.0.0.1.+#   port      - backend TCP port. Required unless unix socket is defined.+#   socket    - unix socket. Highly recommended for security reasons.+#               If defined, IP address and TCP port are ignored.+#+#   cookie_name    - sproxy cookie name. Optional. Default is "sproxy".+#   cookie_domain  - sproxy cookie domain. Optional. Default is the request host name as per RFC2109.+#   cookie_max_age - sproxy cookie shelflife in seconds. Optional. Default is 604800 (7 days).+#   conn_count     - number of connections to keep alive. Optional. Default is 32.+#                    This is specific to Haskell HTTP Client library, and is per host name,+#                    not per backend. HTTP Client's default is 10.+#+# backends:+#   - name: wiki.example.com+#     port: 9090+#     cookie_name: sproxy_example+#     cookie_max_age: 86400+#+backends:+  - port: 8080+
− sproxy.yml.example
@@ -1,176 +0,0 @@---- # Sproxy configuration. Don't remove this line. This is YAML: https://en.wikipedia.org/wiki/YAML--# Logging level: debug, info, warn, error.-# Optional. Default is debug.-#-# log_level: debug--# The port Sproxy listens on (HTTPS).-# Optional. Default is 443.-#-# listen: 443--# 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--# 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).-# Optional. Default is sproxy.-#-# user: sproxy--# Home directory for various files including SQLite3 authorization database.-# Optional. Default is current directory.-#-# home: "."---# 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 if `ssl` = true.-ssl_key: /path/key.pem--# Chain SSL certificate files.-# Optional. Default is an empty list-# Example:-# ssl_cert_chain:-#   - /path/foo.pem-#   - /path/bar.pem-#-# ssl_cert_chain: []---# 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.-# Example:-# database: "user=sproxy-readonly dbname=sproxy port=6001"-#-# database:--# PostgreSQL password file.-# Optional. If specified, sproxy will set PGPASSFILE environment variable pointing to this file-# Example:-# pgpassfile: /run/keys/sproxy.pgpass-#-# pgpassfile:---# YAML file used to fill internal SQLite3 database.-# 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.-# For example see the datafile.yml.example-#-# datafile: /path/data.yml---# A file with arbitrary content used to sign sproxy cookie and other things (secret!).-# Optional. If not specified, a random key is generated on startup, and-# as a consequence, restaring sproxy will invalidate existing user sessions.-# This option could be useful for load-balancing with multiple sproxy instances,-# when all instances must understand cookies created by each other.-# This should not be very large, a few random bytes are fine.-# -# key: /run/keys/sproxy.secret---# Credentials for supported OAuth2 providers.-# Currently supported: "google", "linkedin"-# At least one provider is required.-# Attributes:-#   client_id     - OAuth2 client ID (string)-#   client_secret - OAuth2 client secret. Regardless of its name, this is a file.-#                   The secret is read from the file which you should keep secret.-#                   Only the first line of this file is read.-#-# Example:-# oauth2:-#   google:-#     client_id: "XXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.apps.googleusercontent.com"-#     client_secret: "/run/keys/XXXXXXXXXXXX-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.apps.googleusercontent.com"-#-#   linkedin:-#     client_id: "xxxxxxxxxxxxxx"-#     client_secret: "/run/keys/xxxxxxxxxxxxxx"-#-#-# oauth2:-#   google:-#     client_id:-#     client_secret:---# Backend servers. At least one is required.-# NOTE: backends at TCP port are not secure, even on localhost,-# because any local user can connect to the backend bypassing sproxy-# authentication and authorization.-#-# It is recommended to communicate with backends via unix sockets only.-# Unix sockets should be secured with proper unix file permissions.-#-# Backend attributes:-#   name      - the host name as in the Host HTTP header.-#               May include wildcards * and ?. The first matching-#               backend will be used. Examples: "*.example.com", "wiki.corp.com".-#               Optional. Default is "*". Note, that the name must include-#               port number if non-standard.-#   address   - backend IP address. Optional. Default is 127.0.0.1.-#   port      - backend TCP port. Required unless unix socket is defined.-#   socket    - unix socket. Highly recommended for security reasons.-#               If defined, IP address and TCP port are ignored.-#-#   cookie_name    - sproxy cookie name. Optional. Default is "sproxy".-#   cookie_domain  - sproxy cookie domain. Optional. Default is the request host name as per RFC2109.-#   cookie_max_age - sproxy cookie shelflife in seconds. Optional. Default is 604800 (7 days).-#   conn_count     - number of connections to keep alive. Optional. Default is 32.-#                    This is specific to Haskell HTTP Client library, and is per host name,-#                    not per backend. HTTP Client's default is 10.-#-# backends:-#   - name: wiki.example.com-#     port: 9090-#     cookie_name: sproxy_example-#     cookie_max_age: 86400-#-backends:-  - port: 8080--... # End of configuration. Don't remove this line. This is YAML: https://en.wikipedia.org/wiki/YAML-
sproxy2.cabal view
@@ -1,5 +1,5 @@ name: sproxy2-version: 1.92.0+version: 1.93.0 synopsis: Secure HTTP proxy for authenticating users via OAuth2 description:   Sproxy is secure by default. No requests makes it to the backend@@ -17,9 +17,9 @@ extra-source-files:   ChangeLog.md   README.md-  datafile.yml.example+  datafile.example.yml+  sproxy.example.yml   sproxy.sql-  sproxy.yml.example  source-repository head   type: git
src/Sproxy/Config.hs view
@@ -24,7 +24,7 @@ , cfSslCert      :: Maybe FilePath , cfSslKey       :: Maybe FilePath , cfSslCertChain :: [FilePath]-, cfKey          :: Maybe FilePath+, cfKey          :: Maybe String , cfListen80     :: Maybe Bool , cfHttpsPort    :: Maybe Word16 , cfBackends     :: [BackendConf]@@ -83,7 +83,7 @@  data OAuth2Conf = OAuth2Conf {   oa2ClientId     :: String-, oa2ClientSecret :: FilePath+, oa2ClientSecret :: String } deriving (Show)  instance FromJSON OAuth2Conf where
src/Sproxy/Server.hs view
@@ -5,13 +5,12 @@ import Control.Concurrent (forkIO) import Control.Exception (bracketOnError) import Control.Monad (void, when)-import Data.ByteString as BS (hGetLine, readFile) import Data.ByteString.Char8 (pack) import Data.HashMap.Strict as HM (fromList, lookup, toList) import Data.Maybe (fromMaybe) import Data.Text (Text) import Data.Word (Word16)-import Data.Yaml (decodeFileEither)+import Data.Yaml.Include (decodeFileEither) import Network.HTTP.Client (Manager, ManagerSettings(..), defaultManagerSettings, newManager, socketConnection) import Network.HTTP.Client.Internal (Connection) import Network.Socket ( Socket, Family(AF_INET, AF_UNIX), SockAddr(SockAddrInet, SockAddrUnix),@@ -25,7 +24,7 @@ import System.Environment (setEnv) import System.Exit (exitFailure) import System.FilePath.Glob (compile)-import System.IO (IOMode(ReadMode), hIsEOF, hPutStrLn, stderr, withFile)+import System.IO (hPutStrLn, stderr) import System.Posix.User ( GroupEntry(..), UserEntry(..),   getAllGroupEntries, getRealUserID,   getUserEntryForName, setGroupID, setGroups, setUserID )@@ -47,7 +46,6 @@ server configFile = do   cf <- readConfigFile configFile   Log.start $ cfLogLevel cf-  Log.debug $ show cf    sock <- socket AF_INET Stream 0   setSocketOption sock ReuseAddr 1@@ -78,7 +76,7 @@    key <- maybe            (Log.info "using new random key" >> getEntropy 32)-           (\f -> Log.info ("reading key from " ++ f) >> BS.readFile f)+           (return . pack)            (cfKey cf)    let@@ -139,16 +137,9 @@                   exitFailure     Just provider -> do       Log.info $ "oauth2: adding " ++ show name-      client_secret <- withFile secret_file ReadMode $ \h -> do-        empty <- hIsEOF h-        if empty then do-          Log.error $ "oauth2: empty secret file for "-                    ++ show name ++ ": " ++ show secret_file-          return $ pack ""-        else BS.hGetLine h-      return (name, provider (pack client_id, client_secret))-  where client_id = oa2ClientId cfg-        secret_file = oa2ClientSecret cfg+      return (name, provider (client_id, client_secret))+  where client_id = pack $ oa2ClientId cfg+        client_secret = pack $ oa2ClientSecret cfg   newBackendManager :: BackendConf -> IO Manager