loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

commit 25ccf6c90a369ab60c4bb9666e9542a0b6efd9c6
parent 3491ad6c167d51d0be9c5e4d9c3f8c753bb20cdf
Author: Sebastian Mancke <s.mancke@tarent.de>
Date:   Sun, 20 Nov 2016 13:40:08 +0100

tested and fixed config by enviroment variables

Diffstat:
MDockerfile | 3++-
MREADME.md | 55+++++++++++++++++++++++++++++++++++++++++++++++++------
Mlogin/config.go | 21++++++++++++++++++---
Mlogin/config_test.go | 41+++++++++++++++++++++++++++++++++++++++++
Mmain.go | 4+++-
5 files changed, 113 insertions(+), 11 deletions(-)

diff --git a/Dockerfile b/Dockerfile @@ -1,5 +1,6 @@ FROM alpine +ENV LOGINSRV_HOST=0.0.0.0 LOGINSRV_PORT=80 COPY loginsrv / ENTRYPOINT ["/loginsrv"] -EXPOSE 6789 +EXPOSE 80 diff --git a/README.md b/README.md @@ -1,6 +1,6 @@ # loginsrv -loginsrv is a standalone minimalistic login server providing a (JWT)[https://jwt.io/] login for multiple login backends. +loginsrv is a standalone minimalistic login server providing a [JWT](https://jwt.io/) login for multiple login backends. [![Docker](https://img.shields.io/docker/pulls/tarent/loginsrv.svg)](https://hub.docker.com/r/tarent/loginsrv/) [![Build Status](https://api.travis-ci.org/tarent/loginsrv.svg?branch=master)](https://travis-ci.org/tarent/loginsrv) @@ -9,13 +9,12 @@ loginsrv is a standalone minimalistic login server providing a (JWT)[https://jwt ## Abstract -Loginsrv provides a minimal endpoint for authentication. The login is -then performed against the providers and returned as Json Web Token. +Loginsrv provides a minimal endpoint for authentication. The login is performed against the providers and returned as Json Web Token. ## Supported Provider The following providers (login backends) are supported. -- (OSIAM)[http://osiam.org/] +- [OSIAM](http://osiam.org/) OSIAM is a secure identity management solution providing REST based services for authentication and authorization. It implements the multplie OAuth2 flows, as well as SCIM for managing the user data. - Simple (user/password pairs by configuration) @@ -25,6 +24,51 @@ It implements the multplie OAuth2 flows, as well as SCIM for managing the user d - Backend for checking agains .htaccess file - Caddyserver middleware +## Configuration and Startup +### Config Options +The configuration parameters are as follows. +``` + -backend value + Backend configuration in form 'provider=name,key=val,key=...', can be declared multiple times + -cookie-http-only + Set the cookie with the http only flag (default true) + -cookie-name string + The name of the jwt cookie (default "jwt_token") + -host string + The host to listen on (default "localhost") + -jwt-secret string + The secret to sign the jwt token (default "random key") + -log-level string + The log level (default "info") + -port string + The port to listen on (default "6789") + -success-url string + The url to redirect after login (default "/") + -text-logging + Log in text format instead of json +``` + +### Environment Variables +All of the above Config Options can also be applied as environment variable, where the options name ist written in the way: `LOGINSRV_OPTION_NAME`. +So e.g. `jwt-secret` can be set by environment variable `LOGINSRV_JWT_SECRET`. +To configure multiple backends by environment variable, they can be named in the way: `LOGINSRV_BACKEND, LOGINSRV_BACKEND_FOO, LOGINSRV_BACKEND_BAR, ..` + +### Startup examples +The most simple way to use loginsrv is by the provided docker container. +E.g. configured with the simple provider: +``` +$ docker run -d -p 80:80 tarent/loginsrv -jwt-secret my_secret -backend provider=simple,bob=secret + +$ curl --data "username=bob&password=secret" 127.0.0.1:3000/login +eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib2IifQ.uWoJkSXTLA_RvfLKe12pb4CyxQNxe5_Ovw-N5wfQwkzXz2enbhA9JZf8MmTp9n-TTDcWdY3Fd1SA72_M20G9lQ +``` + +The same configuration could be written with enviroment variables in the way: +``` +$ docker run -d -p 80:80 -e LOGINSRV_JWT_SECRET=my_secret -e LOGINSRV_BACKEND=provider=simple,bob=secret tarent/loginsrv +``` + + ## API ### GET /login @@ -38,7 +82,7 @@ so it can be embedded into an existing layout. Does the login and returns the JWT. Depending on the content-type, and parameters a classical JSON-Rest or a redirect can be performed. -#### Parameters +#### Runtime Parameters | Parameter-Type | Parameter | Description | | | ------------------|--------------------------------------------------|-----------------------------------------------------------|----------| @@ -48,7 +92,6 @@ Does the login and returns the JWT. Depending on the content-type, and parameter | Http-Header | Content-Type: application/json | Take the credentials from the provided json object. | | | Post-Parameter | username | The username | | | Post-Parameter | password | The password | | -| Config-Parameter | success-url | The url to redirect on success | (default /) | #### Possible Return Codes diff --git a/login/config.go b/login/config.go @@ -49,7 +49,17 @@ func ReadConfig() *Config { func readConfig(f *flag.FlagSet, args []string) (*Config, error) { config := DefaultConfig - env.Parse(&config) + err := env.Parse(&config) + if err != nil { + return nil, err + } + + for _, v := range os.Environ() { + pair := strings.SplitN(v, "=", 2) + if len(pair) == 2 && strings.HasPrefix(pair[0], "LOGINSRV_BACKEND") { + (&config.Backends).Set(pair[1]) + } + } f.StringVar(&config.Host, "host", config.Host, "The host to listen on") f.StringVar(&config.Port, "port", config.Port, "The port to listen on") @@ -61,13 +71,18 @@ func readConfig(f *flag.FlagSet, args []string) (*Config, error) { f.StringVar(&config.SuccessUrl, "success-url", config.SuccessUrl, "The url to redirect after login") f.Var(&config.Backends, "backend", "Backend configuration in form 'provider=name,key=val,key=...', can be declared multiple times") - err := f.Parse(args) + err = f.Parse(args) if err != nil { return nil, err } if config.JwtSecret == "random key" { - config.JwtSecret = DefaultConfig.JwtSecret + if s, set := os.LookupEnv("LOGINSRV_JWT_SECRET"); set { + config.JwtSecret = s + + } else { + config.JwtSecret = DefaultConfig.JwtSecret + } } return &config, err diff --git a/login/config_test.go b/login/config_test.go @@ -53,6 +53,47 @@ func TestConfig_ReadConfig(t *testing.T) { assert.Equal(t, expected, cfg) } +func TestConfig_ReadConfigFromEnv(t *testing.T) { + assert.NoError(t, os.Setenv("LOGINSRV_HOST", "host")) + assert.NoError(t, os.Setenv("LOGINSRV_PORT", "port")) + assert.NoError(t, os.Setenv("LOGINSRV_LOG_LEVEL", "loglevel")) + assert.NoError(t, os.Setenv("LOGINSRV_TEXT_LOGGING", "true")) + assert.NoError(t, os.Setenv("LOGINSRV_JWT_SECRET", "jwtsecret")) + assert.NoError(t, os.Setenv("LOGINSRV_SUCCESS_URL", "successurl")) + assert.NoError(t, os.Setenv("LOGINSRV_COOKIE_NAME", "cookiename")) + assert.NoError(t, os.Setenv("LOGINSRV_COOKIE_HTTP_ONLY", "false")) + assert.NoError(t, os.Setenv("LOGINSRV_BACKEND", "provider=simple,foo=bar")) + assert.NoError(t, os.Setenv("LOGINSRV_BACKEND_FOO", "provider=foo")) + assert.NoError(t, os.Setenv("LOGINSRV_BACKEND_BAR", "provider=bar")) + + expected := &Config{ + Host: "host", + Port: "port", + LogLevel: "loglevel", + TextLogging: true, + JwtSecret: "jwtsecret", + SuccessUrl: "successurl", + CookieName: "cookiename", + CookieHttpOnly: false, + Backends: BackendOptions{ + map[string]string{ + "provider": "simple", + "foo": "bar", + }, + map[string]string{ + "provider": "foo", + }, + map[string]string{ + "provider": "bar", + }, + }, + } + + cfg, err := readConfig(flag.NewFlagSet("", flag.ContinueOnError), []string{}) + assert.NoError(t, err) + assert.Equal(t, expected, cfg) +} + func TestConfig_ParseBackendOptions(t *testing.T) { testCases := []struct { input []string diff --git a/main.go b/main.go @@ -21,7 +21,9 @@ func main() { logShutdownEvent() - logging.LifecycleStart(applicationName, config) + configToLog := *config + configToLog.JwtSecret = "..." + logging.LifecycleStart(applicationName, configToLog) h, err := login.NewHandler(config) if err != nil {