Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
52503d9c
Unverified
Commit
52503d9c
authored
Apr 16, 2018
by
Dan Cech
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor authproxy & ldap integration, address comments
parent
c8a0c1e6
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
140 additions
and
93 deletions
+140
-93
pkg/login/ext_user.go
+4
-3
pkg/login/ldap.go
+9
-9
pkg/login/ldap_login_test.go
+1
-1
pkg/login/ldap_test.go
+4
-7
pkg/middleware/auth_proxy.go
+64
-37
pkg/middleware/auth_proxy_test.go
+34
-19
pkg/middleware/middleware_test.go
+4
-1
pkg/services/sqlstore/user_auth.go
+20
-16
No files found.
pkg/login/ext_user.go
View file @
52503d9c
...
...
@@ -78,9 +78,10 @@ func UpsertUser(cmd *m.UpsertUserCommand) error {
func
createUser
(
extUser
*
m
.
ExternalUserInfo
)
(
*
m
.
User
,
error
)
{
cmd
:=
&
m
.
CreateUserCommand
{
Login
:
extUser
.
Login
,
Email
:
extUser
.
Email
,
Name
:
extUser
.
Name
,
Login
:
extUser
.
Login
,
Email
:
extUser
.
Email
,
Name
:
extUser
.
Name
,
SkipOrgSetup
:
len
(
extUser
.
OrgRoles
)
>
0
,
}
if
err
:=
bus
.
Dispatch
(
cmd
);
err
!=
nil
{
return
nil
,
err
...
...
pkg/login/ldap.go
View file @
52503d9c
...
...
@@ -25,7 +25,7 @@ type ILdapConn interface {
type
ILdapAuther
interface
{
Login
(
query
*
m
.
LoginUserQuery
)
error
Sync
SignedInUser
(
ctx
*
m
.
ReqContext
,
signedInUser
*
m
.
SignedInUser
)
error
Sync
User
(
query
*
m
.
LoginUserQuery
)
error
GetGrafanaUserFor
(
ctx
*
m
.
ReqContext
,
ldapUser
*
LdapUserInfo
)
(
*
m
.
User
,
error
)
}
...
...
@@ -125,12 +125,12 @@ func (a *ldapAuther) Login(query *m.LoginUserQuery) error {
return
nil
}
func
(
a
*
ldapAuther
)
SyncSignedInUser
(
ctx
*
m
.
ReqContext
,
signedInUser
*
m
.
SignedInUser
)
error
{
func
(
a
*
ldapAuther
)
SyncUser
(
query
*
m
.
LoginUserQuery
)
error
{
// connect to ldap server
err
:=
a
.
Dial
()
if
err
!=
nil
{
return
err
}
defer
a
.
conn
.
Close
()
err
=
a
.
serverBind
()
...
...
@@ -138,21 +138,21 @@ func (a *ldapAuther) SyncSignedInUser(ctx *m.ReqContext, signedInUser *m.SignedI
return
err
}
ldapUser
,
err
:=
a
.
searchForUser
(
signedInUser
.
Login
)
// find user entry & attributes
ldapUser
,
err
:=
a
.
searchForUser
(
query
.
Username
)
if
err
!=
nil
{
a
.
log
.
Error
(
"Failed searching for user in ldap"
,
"error"
,
err
)
return
err
}
grafanaUser
,
err
:=
a
.
GetGrafanaUserFor
(
ctx
,
ldapUser
)
a
.
log
.
Debug
(
"Ldap User found"
,
"info"
,
spew
.
Sdump
(
ldapUser
))
grafanaUser
,
err
:=
a
.
GetGrafanaUserFor
(
query
.
ReqContext
,
ldapUser
)
if
err
!=
nil
{
return
err
}
signedInUser
.
Login
=
grafanaUser
.
Login
signedInUser
.
Email
=
grafanaUser
.
Email
signedInUser
.
Name
=
grafanaUser
.
Name
query
.
User
=
grafanaUser
return
nil
}
...
...
pkg/login/ldap_login_test.go
View file @
52503d9c
...
...
@@ -127,7 +127,7 @@ func (a *mockLdapAuther) Login(query *m.LoginUserQuery) error {
return
nil
}
func
(
a
*
mockLdapAuther
)
Sync
SignedInUser
(
ctx
*
m
.
ReqContext
,
signedInUser
*
m
.
SignedInUser
)
error
{
func
(
a
*
mockLdapAuther
)
Sync
User
(
query
*
m
.
LoginUserQuery
)
error
{
return
nil
}
...
...
pkg/login/ldap_test.go
View file @
52503d9c
...
...
@@ -91,7 +91,7 @@ func TestLdapAuther(t *testing.T) {
})
Convey
(
"When calling Sync
SignedIn
User"
,
t
,
func
()
{
Convey
(
"When calling SyncUser"
,
t
,
func
()
{
mockLdapConnection
:=
&
mockLdapConn
{}
ldapAuther
:=
NewLdapAuthenticator
(
...
...
@@ -131,11 +131,8 @@ func TestLdapAuther(t *testing.T) {
ldapAutherScenario
(
"When ldapUser found call syncInfo and orgRoles"
,
func
(
sc
*
scenarioContext
)
{
// arrange
signedInUser
:=
&
m
.
SignedInUser
{
Email
:
"roel@test.net"
,
UserId
:
1
,
Name
:
"Roel Gerrits"
,
Login
:
"roelgerrits"
,
query
:=
&
m
.
LoginUserQuery
{
Username
:
"roelgerrits"
,
}
sc
.
userQueryReturns
(
&
m
.
User
{
...
...
@@ -147,7 +144,7 @@ func TestLdapAuther(t *testing.T) {
sc
.
userOrgsQueryReturns
([]
*
m
.
UserOrgDTO
{})
// act
syncErrResult
:=
ldapAuther
.
Sync
SignedInUser
(
nil
,
signedInUser
)
syncErrResult
:=
ldapAuther
.
Sync
User
(
query
)
// assert
So
(
dialCalled
,
ShouldBeTrue
)
...
...
pkg/middleware/auth_proxy.go
View file @
52503d9c
...
...
@@ -44,11 +44,49 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
// if this session has already been authenticated by authProxy just load the user
sessProxyValue
:=
ctx
.
Session
.
Get
(
AUTH_PROXY_SESSION_VAR
)
if
sessProxyValue
!=
nil
&&
sessProxyValue
.
(
string
)
==
proxyHeaderValue
&&
getRequestUserId
(
ctx
)
>
0
{
// if we're using ldap, sync user periodically
if
setting
.
LdapEnabled
{
syncQuery
:=
&
m
.
LoginUserQuery
{
ReqContext
:
ctx
,
Username
:
proxyHeaderValue
,
}
if
err
:=
syncGrafanaUserWithLdapUser
(
syncQuery
);
err
!=
nil
{
if
err
==
login
.
ErrInvalidCredentials
{
ctx
.
Handle
(
500
,
"Unable to authenticate user"
,
err
)
return
false
}
ctx
.
Handle
(
500
,
"Failed to sync user"
,
err
)
return
false
}
}
query
.
UserId
=
getRequestUserId
(
ctx
)
if
err
:=
bus
.
Dispatch
(
query
);
err
!=
nil
{
ctx
.
Handle
(
500
,
"Failed to find user"
,
err
)
return
true
// if we're using ldap, pass authproxy login name to ldap user sync
}
else
if
setting
.
LdapEnabled
{
syncQuery
:=
&
m
.
LoginUserQuery
{
ReqContext
:
ctx
,
Username
:
proxyHeaderValue
,
}
if
err
:=
syncGrafanaUserWithLdapUser
(
syncQuery
);
err
!=
nil
{
if
err
==
login
.
ErrInvalidCredentials
{
ctx
.
Handle
(
500
,
"Unable to authenticate user"
,
err
)
return
false
}
ctx
.
Handle
(
500
,
"Failed to sync user"
,
err
)
return
false
}
if
syncQuery
.
User
==
nil
{
ctx
.
Handle
(
500
,
"Failed to sync user"
,
nil
)
return
false
}
query
.
UserId
=
syncQuery
.
User
.
Id
// no ldap, just use the info we have
}
else
{
extUser
:=
&
m
.
ExternalUserInfo
{
AuthModule
:
"authproxy"
,
...
...
@@ -84,39 +122,28 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
}
query
.
UserId
=
cmd
.
Result
.
Id
}
if
err
:=
bus
.
Dispatch
(
query
);
err
!=
nil
{
ctx
.
Handle
(
500
,
"Failed to find user"
,
err
)
return
true
}
// Make sure that we cannot share a session between different users!
if
getRequestUserId
(
ctx
)
>
0
&&
getRequestUserId
(
ctx
)
!=
query
.
Result
.
UserId
{
// remove session
if
err
:=
ctx
.
Session
.
Destory
(
ctx
.
Context
);
err
!=
nil
{
log
.
Error
(
3
,
"Failed to destroy session, err"
)
}
// initialize a new session
if
err
:=
ctx
.
Session
.
Start
(
ctx
.
Context
);
err
!=
nil
{
log
.
Error
(
3
,
"Failed to start session"
,
err
)
}
}
ctx
.
Session
.
Set
(
AUTH_PROXY_SESSION_VAR
,
proxyHeaderValue
)
if
err
:=
bus
.
Dispatch
(
query
);
err
!=
nil
{
ctx
.
Handle
(
500
,
"Failed to find user"
,
err
)
return
true
}
//
When ldap is enabled, sync userinfo and org roles
if
err
:=
syncGrafanaUserWithLdapUser
(
ctx
,
query
);
err
!=
nil
{
if
err
==
login
.
ErrInvalidCredentials
{
ctx
.
Handle
(
500
,
"Unable to authenticate user"
,
err
)
return
false
//
Make sure that we cannot share a session between different users!
if
getRequestUserId
(
ctx
)
>
0
&&
getRequestUserId
(
ctx
)
!=
query
.
Result
.
UserId
{
// remove session
if
err
:=
ctx
.
Session
.
Destory
(
ctx
.
Context
);
err
!=
nil
{
log
.
Error
(
3
,
"Failed to destroy session, err"
)
}
ctx
.
Handle
(
500
,
"Failed to sync user"
,
err
)
return
false
// initialize a new session
if
err
:=
ctx
.
Session
.
Start
(
ctx
.
Context
);
err
!=
nil
{
log
.
Error
(
3
,
"Failed to start session"
,
err
)
}
}
ctx
.
Session
.
Set
(
AUTH_PROXY_SESSION_VAR
,
proxyHeaderValue
)
ctx
.
SignedInUser
=
query
.
Result
ctx
.
IsSignedIn
=
true
ctx
.
Session
.
Set
(
session
.
SESS_KEY_USERID
,
ctx
.
UserId
)
...
...
@@ -124,29 +151,29 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
return
true
}
var
syncGrafanaUserWithLdapUser
=
func
(
ctx
*
m
.
ReqContext
,
query
*
m
.
GetSignedInUserQuery
)
error
{
if
!
setting
.
LdapEnabled
{
return
nil
}
var
syncGrafanaUserWithLdapUser
=
func
(
query
*
m
.
LoginUserQuery
)
error
{
expireEpoch
:=
time
.
Now
()
.
Add
(
time
.
Duration
(
-
setting
.
AuthProxyLdapSyncTtl
)
*
time
.
Minute
)
.
Unix
()
var
lastLdapSync
int64
if
lastLdapSyncInSession
:=
ctx
.
Session
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
);
lastLdapSyncInSession
!=
nil
{
if
lastLdapSyncInSession
:=
query
.
ReqContext
.
Session
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
);
lastLdapSyncInSession
!=
nil
{
lastLdapSync
=
lastLdapSyncInSession
.
(
int64
)
}
if
lastLdapSync
<
expireEpoch
{
ldapCfg
:=
login
.
LdapCfg
if
len
(
ldapCfg
.
Servers
)
<
1
{
return
fmt
.
Errorf
(
"No LDAP servers available"
)
}
for
_
,
server
:=
range
ldapCfg
.
Servers
{
author
:=
login
.
NewLdapAuthenticator
(
server
)
if
err
:=
author
.
Sync
SignedInUser
(
ctx
,
query
.
Result
);
err
!=
nil
{
if
err
:=
author
.
Sync
User
(
query
);
err
!=
nil
{
return
err
}
}
ctx
.
Session
.
Set
(
session
.
SESS_KEY_LASTLDAPSYNC
,
time
.
Now
()
.
Unix
())
query
.
ReqContext
.
Session
.
Set
(
session
.
SESS_KEY_LASTLDAPSYNC
,
time
.
Now
()
.
Unix
())
}
return
nil
...
...
pkg/middleware/auth_proxy_test.go
View file @
52503d9c
...
...
@@ -26,57 +26,71 @@ func TestAuthProxyWithLdapEnabled(t *testing.T) {
return
&
mockLdapAuther
}
signedInUser
:=
m
.
SignedInUser
{}
query
:=
m
.
GetSignedInUserQuery
{
Result
:
&
signedInUser
}
Convey
(
"When session variable lastLdapSync not set, call syncSignedInUser and set lastLdapSync"
,
func
()
{
Convey
(
"When user logs in, call SyncUser"
,
func
()
{
// arrange
sess
:=
mockSession
{}
sess
:=
newMockSession
()
ctx
:=
m
.
ReqContext
{
Session
:
&
sess
}
So
(
sess
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
),
ShouldBeNil
)
// act
syncGrafanaUserWithLdapUser
(
&
ctx
,
&
query
)
syncGrafanaUserWithLdapUser
(
&
m
.
LoginUserQuery
{
ReqContext
:
&
ctx
,
Username
:
"test"
,
})
// assert
So
(
mockLdapAuther
.
sync
SignedIn
UserCalled
,
ShouldBeTrue
)
So
(
mockLdapAuther
.
syncUserCalled
,
ShouldBeTrue
)
So
(
sess
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
),
ShouldBeGreaterThan
,
0
)
})
Convey
(
"When session variable not expired, don't sync and don't change session var"
,
func
()
{
// arrange
sess
:=
mockSession
{}
sess
:=
newMockSession
()
ctx
:=
m
.
ReqContext
{
Session
:
&
sess
}
now
:=
time
.
Now
()
.
Unix
()
sess
.
Set
(
session
.
SESS_KEY_LASTLDAPSYNC
,
now
)
sess
.
Set
(
AUTH_PROXY_SESSION_VAR
,
"test"
)
// act
syncGrafanaUserWithLdapUser
(
&
ctx
,
&
query
)
syncGrafanaUserWithLdapUser
(
&
m
.
LoginUserQuery
{
ReqContext
:
&
ctx
,
Username
:
"test"
,
})
// assert
So
(
sess
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
),
ShouldEqual
,
now
)
So
(
mockLdapAuther
.
sync
SignedIn
UserCalled
,
ShouldBeFalse
)
So
(
mockLdapAuther
.
syncUserCalled
,
ShouldBeFalse
)
})
Convey
(
"When lastldapsync is expired, session variable should be updated"
,
func
()
{
// arrange
sess
:=
mockSession
{}
sess
:=
newMockSession
()
ctx
:=
m
.
ReqContext
{
Session
:
&
sess
}
expiredTime
:=
time
.
Now
()
.
Add
(
time
.
Duration
(
-
120
)
*
time
.
Minute
)
.
Unix
()
sess
.
Set
(
session
.
SESS_KEY_LASTLDAPSYNC
,
expiredTime
)
sess
.
Set
(
AUTH_PROXY_SESSION_VAR
,
"test"
)
// act
syncGrafanaUserWithLdapUser
(
&
ctx
,
&
query
)
syncGrafanaUserWithLdapUser
(
&
m
.
LoginUserQuery
{
ReqContext
:
&
ctx
,
Username
:
"test"
,
})
// assert
So
(
sess
.
Get
(
session
.
SESS_KEY_LASTLDAPSYNC
),
ShouldBeGreaterThan
,
expiredTime
)
So
(
mockLdapAuther
.
sync
SignedIn
UserCalled
,
ShouldBeTrue
)
So
(
mockLdapAuther
.
syncUserCalled
,
ShouldBeTrue
)
})
})
}
type
mockSession
struct
{
value
interface
{}
value
map
[
interface
{}]
interface
{}
}
func
newMockSession
()
mockSession
{
session
:=
mockSession
{}
session
.
value
=
make
(
map
[
interface
{}]
interface
{})
return
session
}
func
(
s
*
mockSession
)
Start
(
c
*
macaron
.
Context
)
error
{
...
...
@@ -84,15 +98,16 @@ func (s *mockSession) Start(c *macaron.Context) error {
}
func
(
s
*
mockSession
)
Set
(
k
interface
{},
v
interface
{})
error
{
s
.
value
=
v
s
.
value
[
k
]
=
v
return
nil
}
func
(
s
*
mockSession
)
Get
(
k
interface
{})
interface
{}
{
return
s
.
value
return
s
.
value
[
k
]
}
func
(
s
*
mockSession
)
Delete
(
k
interface
{})
interface
{}
{
delete
(
s
.
value
,
k
)
return
nil
}
...
...
@@ -113,15 +128,15 @@ func (s *mockSession) RegenerateId(c *macaron.Context) error {
}
type
mockLdapAuthenticator
struct
{
sync
SignedIn
UserCalled
bool
syncUserCalled
bool
}
func
(
a
*
mockLdapAuthenticator
)
Login
(
query
*
m
.
LoginUserQuery
)
error
{
return
nil
}
func
(
a
*
mockLdapAuthenticator
)
Sync
SignedInUser
(
ctx
*
m
.
ReqContext
,
signedInUser
*
m
.
SignedInUser
)
error
{
a
.
sync
SignedIn
UserCalled
=
true
func
(
a
*
mockLdapAuthenticator
)
Sync
User
(
query
*
m
.
LoginUserQuery
)
error
{
a
.
syncUserCalled
=
true
return
nil
}
...
...
pkg/middleware/middleware_test.go
View file @
52503d9c
...
...
@@ -176,6 +176,7 @@ func TestMiddlewareContext(t *testing.T) {
setting
.
AuthProxyEnabled
=
true
setting
.
AuthProxyHeaderName
=
"X-WEBAUTH-USER"
setting
.
AuthProxyHeaderProperty
=
"username"
setting
.
LdapEnabled
=
false
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
GetSignedInUserQuery
)
error
{
query
.
Result
=
&
m
.
SignedInUser
{
OrgId
:
2
,
UserId
:
12
}
...
...
@@ -203,6 +204,7 @@ func TestMiddlewareContext(t *testing.T) {
setting
.
AuthProxyHeaderName
=
"X-WEBAUTH-USER"
setting
.
AuthProxyHeaderProperty
=
"username"
setting
.
AuthProxyAutoSignUp
=
true
setting
.
LdapEnabled
=
false
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
GetSignedInUserQuery
)
error
{
if
query
.
UserId
>
0
{
...
...
@@ -333,8 +335,9 @@ func TestMiddlewareContext(t *testing.T) {
setting
.
LdapEnabled
=
true
called
:=
false
syncGrafanaUserWithLdapUser
=
func
(
ctx
*
m
.
ReqContext
,
query
*
m
.
GetSignedI
nUserQuery
)
error
{
syncGrafanaUserWithLdapUser
=
func
(
query
*
m
.
Logi
nUserQuery
)
error
{
called
=
true
query
.
User
=
&
m
.
User
{
Id
:
32
}
return
nil
}
...
...
pkg/services/sqlstore/user_auth.go
View file @
52503d9c
...
...
@@ -26,24 +26,13 @@ func GetUserByAuthInfo(query *m.GetUserByAuthInfoQuery) error {
authQuery
.
AuthId
=
query
.
AuthId
err
=
GetAuthInfo
(
authQuery
)
// if user id was specified and doesn't match the user_auth entry, remove it
if
err
==
nil
&&
query
.
UserId
!=
0
&&
query
.
UserId
!=
authQuery
.
Result
.
UserId
{
err
=
DeleteAuthInfo
(
&
m
.
DeleteAuthInfoCommand
{
UserAuth
:
authQuery
.
Result
,
})
if
err
!=
nil
{
sqlog
.
Error
(
"Error removing user_auth entry"
,
"error"
,
err
)
}
authQuery
.
Result
=
nil
}
else
if
err
==
nil
{
has
,
err
=
x
.
Id
(
authQuery
.
Result
.
UserId
)
.
Get
(
user
)
if
err
!=
m
.
ErrUserNotFound
{
if
err
!=
nil
{
return
err
}
if
!
has
{
// if the user has been deleted then remove the entry
// if user id was specified and doesn't match the user_auth entry, remove it
if
query
.
UserId
!=
0
&&
query
.
UserId
!=
authQuery
.
Result
.
UserId
{
err
=
DeleteAuthInfo
(
&
m
.
DeleteAuthInfoCommand
{
UserAuth
:
authQuery
.
Result
,
})
...
...
@@ -52,9 +41,24 @@ func GetUserByAuthInfo(query *m.GetUserByAuthInfoQuery) error {
}
authQuery
.
Result
=
nil
}
else
{
has
,
err
=
x
.
Id
(
authQuery
.
Result
.
UserId
)
.
Get
(
user
)
if
err
!=
nil
{
return
err
}
if
!
has
{
// if the user has been deleted then remove the entry
err
=
DeleteAuthInfo
(
&
m
.
DeleteAuthInfoCommand
{
UserAuth
:
authQuery
.
Result
,
})
if
err
!=
nil
{
sqlog
.
Error
(
"Error removing user_auth entry"
,
"error"
,
err
)
}
authQuery
.
Result
=
nil
}
}
}
else
if
err
!=
m
.
ErrUserNotFound
{
return
err
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment