Merge pull request #1601 from krishnadurai/feature/static_password_env
Option to add staticPasswords from environment variables
This commit is contained in:
commit
a6b5405c2e
4 changed files with 175 additions and 4 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
@ -51,6 +51,7 @@ jobs:
|
|||
- name: Run tests
|
||||
run: make testall
|
||||
env:
|
||||
DEX_FOO_USER_PASSWORD: $2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy
|
||||
DEX_MYSQL_DATABASE: dex
|
||||
DEX_MYSQL_USER: root
|
||||
DEX_MYSQL_PASSWORD: root
|
||||
|
|
|
@ -85,10 +85,11 @@ type password storage.Password
|
|||
|
||||
func (p *password) UnmarshalJSON(b []byte) error {
|
||||
var data struct {
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
UserID string `json:"userID"`
|
||||
Hash string `json:"hash"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
UserID string `json:"userID"`
|
||||
Hash string `json:"hash"`
|
||||
HashFromEnv string `json:"hashFromEnv"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
|
@ -98,6 +99,9 @@ func (p *password) UnmarshalJSON(b []byte) error {
|
|||
Username: data.Username,
|
||||
UserID: data.UserID,
|
||||
})
|
||||
if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
|
||||
data.Hash = os.Getenv(data.HashFromEnv)
|
||||
}
|
||||
if len(data.Hash) == 0 {
|
||||
return fmt.Errorf("no password hash provided")
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
@ -15,6 +16,8 @@ import (
|
|||
|
||||
var _ = yaml.YAMLToJSON
|
||||
|
||||
const testHashStaticPasswordEnv = "DEX_FOO_USER_PASSWORD"
|
||||
|
||||
func TestValidConfiguration(t *testing.T) {
|
||||
configuration := Config{
|
||||
Issuer: "http://127.0.0.1:5556/dex",
|
||||
|
@ -212,3 +215,163 @@ logger:
|
|||
t.Errorf("got!=want: %s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalConfigWithEnv(t *testing.T) {
|
||||
staticPasswordEnv := os.Getenv(testHashStaticPasswordEnv)
|
||||
if staticPasswordEnv == "" {
|
||||
t.Skipf("test environment variable %q not set, skipping", testHashStaticPasswordEnv)
|
||||
}
|
||||
rawConfig := []byte(`
|
||||
issuer: http://127.0.0.1:5556/dex
|
||||
storage:
|
||||
type: postgres
|
||||
config:
|
||||
host: 10.0.0.1
|
||||
port: 65432
|
||||
maxOpenConns: 5
|
||||
maxIdleConns: 3
|
||||
connMaxLifetime: 30
|
||||
connectionTimeout: 3
|
||||
web:
|
||||
http: 127.0.0.1:5556
|
||||
|
||||
frontend:
|
||||
dir: ./web
|
||||
extra:
|
||||
foo: bar
|
||||
|
||||
staticClients:
|
||||
- id: example-app
|
||||
redirectURIs:
|
||||
- 'http://127.0.0.1:5555/callback'
|
||||
name: 'Example App'
|
||||
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
|
||||
|
||||
oauth2:
|
||||
alwaysShowLoginScreen: true
|
||||
|
||||
connectors:
|
||||
- type: mockCallback
|
||||
id: mock
|
||||
name: Example
|
||||
- type: oidc
|
||||
id: google
|
||||
name: Google
|
||||
config:
|
||||
issuer: https://accounts.google.com
|
||||
clientID: foo
|
||||
clientSecret: bar
|
||||
redirectURI: http://127.0.0.1:5556/dex/callback/google
|
||||
|
||||
enablePasswordDB: true
|
||||
staticPasswords:
|
||||
- email: "admin@example.com"
|
||||
# bcrypt hash of the string "password"
|
||||
hash: "$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"
|
||||
username: "admin"
|
||||
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
|
||||
- email: "foo@example.com"
|
||||
hashFromEnv: "DEX_FOO_USER_PASSWORD"
|
||||
username: "foo"
|
||||
userID: "41331323-6f44-45e6-b3b9-2c4b60c02be5"
|
||||
|
||||
expiry:
|
||||
signingKeys: "7h"
|
||||
idTokens: "25h"
|
||||
authRequests: "25h"
|
||||
|
||||
logger:
|
||||
level: "debug"
|
||||
format: "json"
|
||||
`)
|
||||
|
||||
want := Config{
|
||||
Issuer: "http://127.0.0.1:5556/dex",
|
||||
Storage: Storage{
|
||||
Type: "postgres",
|
||||
Config: &sql.Postgres{
|
||||
NetworkDB: sql.NetworkDB{
|
||||
Host: "10.0.0.1",
|
||||
Port: 65432,
|
||||
MaxOpenConns: 5,
|
||||
MaxIdleConns: 3,
|
||||
ConnMaxLifetime: 30,
|
||||
ConnectionTimeout: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
Web: Web{
|
||||
HTTP: "127.0.0.1:5556",
|
||||
},
|
||||
Frontend: server.WebConfig{
|
||||
Dir: "./web",
|
||||
Extra: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
StaticClients: []storage.Client{
|
||||
{
|
||||
ID: "example-app",
|
||||
Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0",
|
||||
Name: "Example App",
|
||||
RedirectURIs: []string{
|
||||
"http://127.0.0.1:5555/callback",
|
||||
},
|
||||
},
|
||||
},
|
||||
OAuth2: OAuth2{
|
||||
AlwaysShowLoginScreen: true,
|
||||
},
|
||||
StaticConnectors: []Connector{
|
||||
{
|
||||
Type: "mockCallback",
|
||||
ID: "mock",
|
||||
Name: "Example",
|
||||
Config: &mock.CallbackConfig{},
|
||||
},
|
||||
{
|
||||
Type: "oidc",
|
||||
ID: "google",
|
||||
Name: "Google",
|
||||
Config: &oidc.Config{
|
||||
Issuer: "https://accounts.google.com",
|
||||
ClientID: "foo",
|
||||
ClientSecret: "bar",
|
||||
RedirectURI: "http://127.0.0.1:5556/dex/callback/google",
|
||||
},
|
||||
},
|
||||
},
|
||||
EnablePasswordDB: true,
|
||||
StaticPasswords: []password{
|
||||
{
|
||||
Email: "admin@example.com",
|
||||
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
|
||||
Username: "admin",
|
||||
UserID: "08a8684b-db88-4b73-90a9-3cd1661f5466",
|
||||
},
|
||||
{
|
||||
Email: "foo@example.com",
|
||||
Hash: []byte("$2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy"),
|
||||
Username: "foo",
|
||||
UserID: "41331323-6f44-45e6-b3b9-2c4b60c02be5",
|
||||
},
|
||||
},
|
||||
Expiry: Expiry{
|
||||
SigningKeys: "7h",
|
||||
IDTokens: "25h",
|
||||
AuthRequests: "25h",
|
||||
},
|
||||
Logger: Logger{
|
||||
Level: "debug",
|
||||
Format: "json",
|
||||
},
|
||||
}
|
||||
|
||||
var c Config
|
||||
if err := yaml.Unmarshal(rawConfig, &c); err != nil {
|
||||
t.Fatalf("failed to decode config: %v", err)
|
||||
}
|
||||
if diff := pretty.Compare(c, want); diff != "" {
|
||||
t.Errorf("got!=want: %s", diff)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,6 +292,9 @@ type Password struct {
|
|||
// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
|
||||
Hash []byte `json:"hash"`
|
||||
|
||||
// Bcrypt encoded hash of the password set in environment variable of this name.
|
||||
HashFromEnv string `json:"hashFromEnv"`
|
||||
|
||||
// Optional username to display. NOT used during login.
|
||||
Username string `json:"username"`
|
||||
|
||||
|
|
Reference in a new issue