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
|
- name: Run tests
|
||||||
run: make testall
|
run: make testall
|
||||||
env:
|
env:
|
||||||
|
DEX_FOO_USER_PASSWORD: $2a$10$33EMT0cVYVlPy6WAMCLsceLYjWhuHpbz5yuZxu/GAFj03J9Lytjuy
|
||||||
DEX_MYSQL_DATABASE: dex
|
DEX_MYSQL_DATABASE: dex
|
||||||
DEX_MYSQL_USER: root
|
DEX_MYSQL_USER: root
|
||||||
DEX_MYSQL_PASSWORD: root
|
DEX_MYSQL_PASSWORD: root
|
||||||
|
|
|
@ -85,10 +85,11 @@ type password storage.Password
|
||||||
|
|
||||||
func (p *password) UnmarshalJSON(b []byte) error {
|
func (p *password) UnmarshalJSON(b []byte) error {
|
||||||
var data struct {
|
var data struct {
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
|
HashFromEnv string `json:"hashFromEnv"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(b, &data); err != nil {
|
if err := json.Unmarshal(b, &data); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -98,6 +99,9 @@ func (p *password) UnmarshalJSON(b []byte) error {
|
||||||
Username: data.Username,
|
Username: data.Username,
|
||||||
UserID: data.UserID,
|
UserID: data.UserID,
|
||||||
})
|
})
|
||||||
|
if len(data.Hash) == 0 && len(data.HashFromEnv) > 0 {
|
||||||
|
data.Hash = os.Getenv(data.HashFromEnv)
|
||||||
|
}
|
||||||
if len(data.Hash) == 0 {
|
if len(data.Hash) == 0 {
|
||||||
return fmt.Errorf("no password hash provided")
|
return fmt.Errorf("no password hash provided")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
@ -15,6 +16,8 @@ import (
|
||||||
|
|
||||||
var _ = yaml.YAMLToJSON
|
var _ = yaml.YAMLToJSON
|
||||||
|
|
||||||
|
const testHashStaticPasswordEnv = "DEX_FOO_USER_PASSWORD"
|
||||||
|
|
||||||
func TestValidConfiguration(t *testing.T) {
|
func TestValidConfiguration(t *testing.T) {
|
||||||
configuration := Config{
|
configuration := Config{
|
||||||
Issuer: "http://127.0.0.1:5556/dex",
|
Issuer: "http://127.0.0.1:5556/dex",
|
||||||
|
@ -212,3 +215,163 @@ logger:
|
||||||
t.Errorf("got!=want: %s", diff)
|
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
|
// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
|
||||||
Hash []byte `json:"hash"`
|
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.
|
// Optional username to display. NOT used during login.
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
|
||||||
|
|
Reference in a new issue