Skip to content

Commit a487ee3

Browse files
committed
Fixes #5
Configuration options: cookie_credentials - set to true to use cookie instead of session for storing Keystone password credential_aes_key - 32-char encryption key. If set, this key is used to encrypt/decrypt the stored Keystone password
1 parent 32a011e commit a487ee3

File tree

5 files changed

+101
-17
lines changed

5 files changed

+101
-17
lines changed

conf/sample.ini

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,11 @@
268268
;viewer_roles =
269269
;verify_ssl_cert = true
270270
;root_ca_pem_file = /etc/grafana/Keystone_CA.crt
271+
# Whether to store keystone password in a cookie (true) or in a session variable (false)
272+
;cookie_credentials = true
273+
# Encryption key for storing keystone password (empty = no encryption)
274+
# AES key should be 32 bytes
275+
;credential_aes_key = 123456789,123456789,123456789,12
271276

272277
#################################### SMTP / Emailing ##########################
273278
[smtp]

pkg/api/keystone/keystone.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ package keystone
33
import (
44
"time"
55

6+
"crypto/aes"
7+
"crypto/cipher"
8+
"crypto/rand"
9+
"encoding/base64"
610
"errors"
711
"github.com/grafana/grafana/pkg/bus"
12+
"github.com/grafana/grafana/pkg/log"
813
"github.com/grafana/grafana/pkg/middleware"
914
m "github.com/grafana/grafana/pkg/models"
1015
"github.com/grafana/grafana/pkg/setting"
16+
"io"
1117
)
1218

1319
const (
@@ -19,7 +25,13 @@ const (
1925

2026
func getUserName(c *middleware.Context) (string, error) {
2127
var keystoneUserIdObj interface{}
22-
if keystoneUserIdObj = c.Session.Get(middleware.SESS_KEY_USERID); keystoneUserIdObj == nil {
28+
if setting.KeystoneCookieCredentials {
29+
if keystoneUserIdObj = c.GetCookie(setting.CookieUserName); keystoneUserIdObj == nil {
30+
return "", errors.New("Couldn't find cookie containing keystone userId")
31+
} else {
32+
return keystoneUserIdObj.(string), nil
33+
}
34+
} else if keystoneUserIdObj = c.Session.Get(middleware.SESS_KEY_USERID); keystoneUserIdObj == nil {
2335
return "", errors.New("Session timed out trying to get keystone userId")
2436
}
2537

@@ -53,8 +65,28 @@ func getNewToken(c *middleware.Context) (string, error) {
5365
}
5466

5567
var keystonePasswordObj interface{}
56-
if keystonePasswordObj = c.Session.Get(middleware.SESS_KEY_PASSWORD); keystonePasswordObj == nil {
68+
if setting.KeystoneCookieCredentials {
69+
if setting.KeystoneCredentialAesKey != "" {
70+
c.GetCookie(middleware.SESS_KEY_PASSWORD)
71+
} else {
72+
keystonePasswordObj = c.GetCookie(middleware.SESS_KEY_PASSWORD)
73+
}
74+
if keystonePasswordObj == nil {
75+
return "", errors.New("Couldn't find cookie containing keystone password")
76+
} else {
77+
log.Debug("Got password from cookie")
78+
}
79+
} else if keystonePasswordObj = c.Session.Get(middleware.SESS_KEY_PASSWORD); keystonePasswordObj == nil {
5780
return "", errors.New("Session timed out trying to get keystone password")
81+
} else if keystonePasswordObj != nil {
82+
log.Debug("Got password from session")
83+
}
84+
85+
if setting.KeystoneCredentialAesKey != "" {
86+
keystonePasswordObj = decryptPassword(keystonePasswordObj.(string))
87+
log.Debug("Decrypted password")
88+
} else {
89+
log.Warn("Password stored in cleartext!")
5890
}
5991

6092
auth := Auth_data{
@@ -65,6 +97,11 @@ func getNewToken(c *middleware.Context) (string, error) {
6597
Server: setting.KeystoneURL,
6698
}
6799
if err := AuthenticateScoped(&auth); err != nil {
100+
if setting.KeystoneCookieCredentials {
101+
c.SetCookie(middleware.SESS_KEY_PASSWORD, "", 0)
102+
} else {
103+
c.Session.Set(middleware.SESS_KEY_PASSWORD, nil)
104+
}
68105
return "", err
69106
}
70107

@@ -124,3 +161,34 @@ func GetToken(c *middleware.Context) (string, error) {
124161
}
125162
return token, nil
126163
}
164+
165+
func EncryptPassword(password string) string {
166+
key := []byte(setting.KeystoneCredentialAesKey)
167+
block, err := aes.NewCipher(key)
168+
if err != nil {
169+
log.Error(3, "Error: NewCipher(%d bytes) = %s", len(setting.KeystoneCredentialAesKey), err)
170+
}
171+
ciphertext := make([]byte, aes.BlockSize+len(password))
172+
iv := ciphertext[:aes.BlockSize]
173+
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
174+
log.Error(3, "Error: %s", err)
175+
}
176+
stream := cipher.NewOFB(block, iv)
177+
stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(password))
178+
179+
return base64.StdEncoding.EncodeToString(ciphertext)
180+
}
181+
182+
func decryptPassword(base64ciphertext string) string {
183+
key := []byte(setting.KeystoneCredentialAesKey)
184+
block, err := aes.NewCipher(key)
185+
if err != nil {
186+
log.Error(3, "Error: NewCipher(%d bytes) = %s", len(setting.KeystoneCredentialAesKey), err)
187+
}
188+
ciphertext, err := base64.StdEncoding.DecodeString(base64ciphertext)
189+
iv := ciphertext[:aes.BlockSize]
190+
password := make([]byte, len(ciphertext)-aes.BlockSize)
191+
stream := cipher.NewOFB(block, iv)
192+
stream.XORKeyStream(password, ciphertext[aes.BlockSize:])
193+
return string(password)
194+
}

pkg/api/login.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"net/url"
55

66
"github.com/grafana/grafana/pkg/api/dtos"
7+
"github.com/grafana/grafana/pkg/api/keystone"
78
"github.com/grafana/grafana/pkg/bus"
89
"github.com/grafana/grafana/pkg/log"
910
"github.com/grafana/grafana/pkg/login"
@@ -112,7 +113,14 @@ func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) Response {
112113
loginUserWithUser(user, c)
113114

114115
if setting.KeystoneEnabled {
115-
c.Session.Set(middleware.SESS_KEY_PASSWORD, cmd.Password)
116+
if setting.KeystoneCredentialAesKey != "" {
117+
cmd.Password = keystone.EncryptPassword(cmd.Password)
118+
}
119+
if setting.KeystoneCookieCredentials {
120+
c.SetCookie(middleware.SESS_KEY_PASSWORD, cmd.Password)
121+
} else {
122+
c.Session.Set(middleware.SESS_KEY_PASSWORD, cmd.Password)
123+
}
116124
}
117125

118126
result := map[string]interface{}{

pkg/middleware/session.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import (
1212
)
1313

1414
const (
15-
SESS_KEY_USERID = "uid"
15+
SESS_KEY_USERID = "uid"
1616
SESS_KEY_OAUTH_STATE = "state"
17-
SESS_KEY_APIKEY = "apikey_id" // used fror render requests with api keys
18-
SESS_KEY_PASSWORD = "password"
17+
SESS_KEY_PASSWORD = "password"
1918
)
2019

2120
var sessionManager *session.Manager

pkg/setting/setting.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,19 @@ var (
139139
LdapAllowSignup bool = true
140140

141141
// Keystone
142-
KeystoneEnabled bool
143-
KeystoneURL string
144-
KeystoneDefaultDomain string
145-
KeystoneDefaultRole string
146-
KeystoneViewerRoles []string
147-
KeystoneReadEditorRoles []string
148-
KeystoneEditorRoles []string
149-
KeystoneAdminRoles []string
150-
KeystoneGlobalAdminRoles []string
151-
KeystoneVerifySSLCert bool
152-
KeystoneRootCAPEMFile string
142+
KeystoneEnabled bool
143+
KeystoneCookieCredentials bool
144+
KeystoneCredentialAesKey string
145+
KeystoneURL string
146+
KeystoneDefaultDomain string
147+
KeystoneDefaultRole string
148+
KeystoneViewerRoles []string
149+
KeystoneReadEditorRoles []string
150+
KeystoneEditorRoles []string
151+
KeystoneAdminRoles []string
152+
KeystoneGlobalAdminRoles []string
153+
KeystoneVerifySSLCert bool
154+
KeystoneRootCAPEMFile string
153155

154156
// SMTP email settings
155157
Smtp SmtpSettings
@@ -572,6 +574,8 @@ func NewConfigContext(args *CommandLineArgs) error {
572574

573575
keystone := Cfg.Section("auth.keystone")
574576
KeystoneEnabled = keystone.Key("enabled").MustBool(false)
577+
KeystoneCookieCredentials = keystone.Key("cookie_credentials").MustBool(false)
578+
KeystoneCredentialAesKey = keystone.Key("credential_aes_key").String()
575579
KeystoneURL = keystone.Key("auth_url").String()
576580
KeystoneDefaultDomain = keystone.Key("default_domain").String()
577581
KeystoneDefaultRole = keystone.Key("default_role").String()

0 commit comments

Comments
 (0)