Skip to content

Commit e882fee

Browse files
author
Ryan Bak
committed
Merge branch 'v2.6.0-keystone' into master-keystone
Conflicts: public/app/core/utils/rangeutil.ts
2 parents f842e28 + 10d7241 commit e882fee

File tree

11 files changed

+921
-0
lines changed

11 files changed

+921
-0
lines changed

conf/defaults.ini

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,20 @@ auto_sign_up = true
230230
enabled = false
231231
config_file = /etc/grafana/ldap.toml
232232

233+
#################################### Auth Keystone ##########################
234+
[auth.keystone]
235+
enabled = false
236+
auth_url = http://localhost:5000
237+
default_domain = default
238+
#default_role = Viewer
239+
global_admin_roles =
240+
admin_roles = admin
241+
editor_roles = _member_
242+
read_editor_roles =
243+
viewer_roles =
244+
verify_ssl_cert = true
245+
root_ca_pem_file =
246+
233247
#################################### SMTP / Emailing ##########################
234248
[smtp]
235249
enabled = false

conf/sample.ini

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,21 @@ check_for_updates = true
213213
;enabled = false
214214
;config_file = /etc/grafana/ldap.toml
215215

216+
#################################### Auth Keystone ##########################
217+
[auth.keystone]
218+
;enabled = false
219+
;auth_url = http://localhost:5000
220+
;v3 = false
221+
;default_domain = default
222+
;default_role = Viewer
223+
;global_admin_roles =
224+
;admin_roles = admin
225+
;editor_roles = _member_
226+
;read_editor_roles =
227+
;viewer_roles =
228+
;verify_ssl_cert = true
229+
;root_ca_pem_file = /etc/grafana/Keystone_CA.crt
230+
216231
#################################### SMTP / Emailing ##########################
217232
[smtp]
218233
;enabled = false

pkg/api/dataproxy.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"github.com/grafana/grafana/pkg/api/cloudwatch"
12+
"github.com/grafana/grafana/pkg/api/keystone"
1213
"github.com/grafana/grafana/pkg/bus"
1314
"github.com/grafana/grafana/pkg/metrics"
1415
"github.com/grafana/grafana/pkg/middleware"
@@ -98,6 +99,15 @@ func ProxyDataSourceRequest(c *middleware.Context) {
9899
}
99100
}
100101

102+
keystoneAuth, _ := ds.JsonData["keystoneAuth"].(bool)
103+
if keystoneAuth {
104+
token, err := keystone.GetToken(c)
105+
if err != nil {
106+
c.JsonApiErr(500, "Failed to get keystone token", err)
107+
}
108+
c.Req.Request.Header["X-Auth-Token"] = []string{token}
109+
}
110+
101111
if ds.Type == m.DS_CLOUDWATCH {
102112
cloudwatch.HandleRequest(c, ds)
103113
} else {

pkg/api/keystone/keystone.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package keystone
2+
3+
import (
4+
"time"
5+
6+
"errors"
7+
"github.com/grafana/grafana/pkg/bus"
8+
"github.com/grafana/grafana/pkg/middleware"
9+
m "github.com/grafana/grafana/pkg/models"
10+
"github.com/grafana/grafana/pkg/setting"
11+
)
12+
13+
const (
14+
SESS_TOKEN = "keystone_token"
15+
SESS_TOKEN_EXPIRATION = "keystone_expiration"
16+
SESS_TOKEN_PROJECT = "keystone_project"
17+
TOKEN_BUFFER_TIME = 5 // Tokens refresh if the token will expire in less than this many minutes
18+
)
19+
20+
func getUserName(c *middleware.Context) (string, error) {
21+
var keystoneUserIdObj interface{}
22+
if keystoneUserIdObj = c.Session.Get(middleware.SESS_KEY_USERID); keystoneUserIdObj == nil {
23+
return "", errors.New("Session timed out trying to get keystone userId")
24+
}
25+
26+
userQuery := m.GetUserByIdQuery{Id: keystoneUserIdObj.(int64)}
27+
if err := bus.Dispatch(&userQuery); err != nil {
28+
if err == m.ErrUserNotFound {
29+
return "", err
30+
}
31+
}
32+
return userQuery.Result.Login, nil
33+
}
34+
35+
func getOrgName(c *middleware.Context) (string, error) {
36+
orgQuery := m.GetOrgByIdQuery{Id: c.OrgId}
37+
if err := bus.Dispatch(&orgQuery); err != nil {
38+
if err == m.ErrOrgNotFound {
39+
return "", err
40+
}
41+
}
42+
return orgQuery.Result.Name, nil
43+
}
44+
45+
func getNewToken(c *middleware.Context) (string, error) {
46+
var username, project string
47+
var err error
48+
if username, err = getUserName(c); err != nil {
49+
return "", err
50+
}
51+
if project, err = getOrgName(c); err != nil {
52+
return "", err
53+
}
54+
55+
var keystonePasswordObj interface{}
56+
if keystonePasswordObj = c.Session.Get(middleware.SESS_KEY_PASSWORD); keystonePasswordObj == nil {
57+
return "", errors.New("Session timed out trying to get keystone password")
58+
}
59+
60+
auth := Auth_data{
61+
Username: username,
62+
Project: project,
63+
Password: keystonePasswordObj.(string),
64+
Domain: setting.KeystoneDefaultDomain,
65+
Server: setting.KeystoneURL,
66+
}
67+
if err := AuthenticateScoped(&auth); err != nil {
68+
return "", err
69+
}
70+
71+
c.Session.Set(SESS_TOKEN, auth.Token)
72+
c.Session.Set(SESS_TOKEN_EXPIRATION, auth.Expiration)
73+
c.Session.Set(SESS_TOKEN_PROJECT, project)
74+
// in keystone v3 the token is in the response header
75+
return auth.Token, nil
76+
}
77+
78+
func validateCurrentToken(c *middleware.Context) (bool, error) {
79+
token := c.Session.Get(SESS_TOKEN)
80+
if token == nil {
81+
return false, nil
82+
}
83+
84+
expiration_obj := c.Session.Get(SESS_TOKEN_EXPIRATION)
85+
if expiration_obj == nil || expiration_obj.(string) == "" {
86+
return false, nil
87+
}
88+
expiration, err := time.Parse(time.RFC3339, expiration_obj.(string))
89+
if err != nil {
90+
return false, err
91+
}
92+
93+
now := time.Now()
94+
if now.After(expiration.Add(-TOKEN_BUFFER_TIME * time.Minute)) {
95+
return false, nil
96+
}
97+
98+
project := c.Session.Get(SESS_TOKEN_PROJECT)
99+
org, err := getOrgName(c)
100+
if err != nil {
101+
return false, err
102+
}
103+
if org != project {
104+
return false, nil
105+
}
106+
107+
return true, nil
108+
}
109+
110+
func GetToken(c *middleware.Context) (string, error) {
111+
var token string
112+
var err error
113+
valid, err := validateCurrentToken(c)
114+
if valid {
115+
116+
var sessionTokenObj interface{}
117+
if sessionTokenObj = c.Session.Get(SESS_TOKEN); sessionTokenObj == nil {
118+
return "", errors.New("Session timed out trying to get token")
119+
}
120+
return sessionTokenObj.(string), nil
121+
}
122+
if token, err = getNewToken(c); err != nil {
123+
return "", err
124+
}
125+
return token, nil
126+
}

0 commit comments

Comments
 (0)