@@ -3,11 +3,17 @@ package keystone
3
3
import (
4
4
"time"
5
5
6
+ "crypto/aes"
7
+ "crypto/cipher"
8
+ "crypto/rand"
9
+ "encoding/base64"
6
10
"errors"
7
11
"github.com/grafana/grafana/pkg/bus"
12
+ "github.com/grafana/grafana/pkg/log"
8
13
"github.com/grafana/grafana/pkg/middleware"
9
14
m "github.com/grafana/grafana/pkg/models"
10
15
"github.com/grafana/grafana/pkg/setting"
16
+ "io"
11
17
)
12
18
13
19
const (
@@ -19,7 +25,13 @@ const (
19
25
20
26
func getUserName (c * middleware.Context ) (string , error ) {
21
27
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 {
23
35
return "" , errors .New ("Session timed out trying to get keystone userId" )
24
36
}
25
37
@@ -53,8 +65,23 @@ func getNewToken(c *middleware.Context) (string, error) {
53
65
}
54
66
55
67
var keystonePasswordObj interface {}
56
- if keystonePasswordObj = c .Session .Get (middleware .SESS_KEY_PASSWORD ); keystonePasswordObj == nil {
68
+ if setting .KeystoneCookieCredentials {
69
+ if keystonePasswordObj = c .GetCookie (middleware .SESS_KEY_PASSWORD ); keystonePasswordObj == nil {
70
+ return "" , errors .New ("Couldn't find cookie containing keystone password" )
71
+ } else {
72
+ log .Debug ("Got password from cookie" )
73
+ }
74
+ } else if keystonePasswordObj = c .Session .Get (middleware .SESS_KEY_PASSWORD ); keystonePasswordObj == nil {
57
75
return "" , errors .New ("Session timed out trying to get keystone password" )
76
+ } else if keystonePasswordObj != nil {
77
+ log .Debug ("Got password from session" )
78
+ }
79
+
80
+ if setting .KeystoneCredentialAesKey != "" {
81
+ keystonePasswordObj = decryptPassword (keystonePasswordObj .(string ))
82
+ log .Debug ("Decrypted password" )
83
+ } else {
84
+ log .Warn ("Password stored in cleartext!" )
58
85
}
59
86
60
87
auth := Auth_data {
@@ -65,6 +92,11 @@ func getNewToken(c *middleware.Context) (string, error) {
65
92
Server : setting .KeystoneURL ,
66
93
}
67
94
if err := AuthenticateScoped (& auth ); err != nil {
95
+ if setting .KeystoneCookieCredentials {
96
+ c .SetCookie (middleware .SESS_KEY_PASSWORD , "" , - 1 , setting .AppSubUrl + "/" , nil , middleware .IsSecure (c ), true )
97
+ } else {
98
+ c .Session .Set (middleware .SESS_KEY_PASSWORD , nil )
99
+ }
68
100
return "" , err
69
101
}
70
102
@@ -124,3 +156,42 @@ func GetToken(c *middleware.Context) (string, error) {
124
156
}
125
157
return token , nil
126
158
}
159
+
160
+ func EncryptPassword (password string ) string {
161
+ key := []byte (setting .KeystoneCredentialAesKey )
162
+ block , err := aes .NewCipher (key )
163
+ if err != nil {
164
+ log .Error (3 , "Error: NewCipher(%d bytes) = %s" , len (setting .KeystoneCredentialAesKey ), err )
165
+ }
166
+ ciphertext := make ([]byte , aes .BlockSize + len (password ))
167
+ iv := ciphertext [:aes .BlockSize ]
168
+ if _ , err := io .ReadFull (rand .Reader , iv ); err != nil {
169
+ log .Error (3 , "Error: %s" , err )
170
+ }
171
+ stream := cipher .NewOFB (block , iv )
172
+ stream .XORKeyStream (ciphertext [aes .BlockSize :], []byte (password ))
173
+
174
+ return base64 .StdEncoding .EncodeToString (ciphertext )
175
+ }
176
+
177
+ func decryptPassword (base64ciphertext string ) string {
178
+ key := []byte (setting .KeystoneCredentialAesKey )
179
+ block , err := aes .NewCipher (key )
180
+ if err != nil {
181
+ log .Error (3 , "Error: NewCipher(%d bytes) = %s" , len (setting .KeystoneCredentialAesKey ), err )
182
+ }
183
+ ciphertext , err := base64 .StdEncoding .DecodeString (base64ciphertext )
184
+ if err != nil {
185
+ log .Error (3 , "Error: %s" , err )
186
+ return ""
187
+ }
188
+ iv := ciphertext [:aes .BlockSize ]
189
+ if aes .BlockSize > len (ciphertext ) {
190
+ log .Error (3 , "Error: ciphertext %s is shorter than AES blocksize %d" , ciphertext , aes .BlockSize )
191
+ return ""
192
+ }
193
+ password := make ([]byte , len (ciphertext )- aes .BlockSize )
194
+ stream := cipher .NewOFB (block , iv )
195
+ stream .XORKeyStream (password , ciphertext [aes .BlockSize :])
196
+ return string (password )
197
+ }
0 commit comments