Influxdb授权验证流程分析
Qurey语句权限验证
关于Influxdb的验证逻辑,我们可以先参考官方文档: Authentication and authorization in InfluxDB
1.1 在配置文件时,[http] auth-enabled = true将开启授权验证我们从
appendHTTPDService(cmd/influxdb/run/server.go)入手,在处理http request时要作授权验证,先要创建授权验证对象:
srv.Handler.QueryAuthorizer = meta.NewQueryAuthorizer(s.MetaClient) srv.Handler.WriteAuthorizer = meta.NewWriteAuthorizer(s.MetaClient)
Query验证
meta.QueryAuthorizer(services/meta/data.go)
// QueryAuthorizer determines whether a user is authorized to execute a given query.type QueryAuthorizer struct {
Client *Client // MetaClient}验证流程图:
influxdb_authorizer.png
通过上面这张图我们看到授权验证所有的接口都定义在
type Authorizer interface中
type Authorizer interface { // AuthorizeDatabase indicates whether the given Privilege is authorized on the database with the given name.
AuthorizeDatabase(p influxql.Privilege, name string) bool
// AuthorizeQuery returns an error if the query cannot be executed
AuthorizeQuery(database string, query *influxql.Query) error // AuthorizeSeriesRead determines if a series is authorized for reading
AuthorizeSeriesRead(database string, measurement []byte, tags models.Tags) bool
// AuthorizeSeriesWrite determines if a series is authorized for writing
AuthorizeSeriesWrite(database string, measurement []byte, tags models.Tags) bool}首先看一下 `QueryAuthorizer.AuthorizeQuery, 以注释的方式给出说明
func (a *QueryAuthorizer) AuthorizeQuery(u User, query *influxql.Query, database string) error { // Special case if no users exist.
if n := a.Client.UserCount(); n == 0 { // Ensure there is at least one statement.
if len(query.Statements) > 0 { // First statement in the query must create a user with admin privilege.
// 如果没有任何的用户,query的一个请求必须是Create Admin User
cu, ok := query.Statements[0].(*influxql.CreateUserStatement) if ok && cu.Admin { return nil
}
} //Inlufxdb的验证流程规定,如果开启了授权验证,但还没有创建任何用户,则返回用户下面这个错误
return &ErrAuthorize{
Query: query,
Database: database,
Message: "create admin user first or disable authentication",
}
} //请求中没有user信息,则返回用户下面这个错误
if u == nil { return &ErrAuthorize{
Query: query,
Database: database,
Message: "no user provided",
}
} // 调用User.AuthorizeQuery继续验证
return u.AuthorizeQuery(database, query)
}接着看一下
UserInfo.AuthorizeQuery
func (u *UserInfo) AuthorizeQuery(database string, query *influxql.Query) error { // Admin privilege allows the user to execute all statements.
// Admin用户有一切授权,不用再继续验证
if u.Admin { return nil
} // query里的每条statement的所需的所有privilege都需要逐一验证
for _, stmt := range query.Statements {
privs, err := stmt.RequiredPrivileges() for _, p := range privs { if p.Admin { // 走到这里说明当前用户一定不是admin用户,但当前statement又需要admin privilege, 则返回如下错
return &ErrAuthorize{
Query: query,
User: u.Name,
Database: database,
Message: fmt.Sprintf("statement '%s', requires admin privilege", stmt),
}
}
db := p.Name if db == "" {
db = database
} // 调用u.AuthorizeDatabase进一步验证
if !u.AuthorizeDatabase(p.Privilege, db) { return &ErrAuthorize{
Query: query,
User: u.Name,
Database: database,
Message: fmt.Sprintf("statement '%s', requires %s on %s", stmt, p.Privilege.String(), db),
}
}
}
} return nil}最后看一下
UserInfo.AuthorizeDatabase和UserInfo的定义:
type UserInfo struct {
// User's name.
Name string
// Hashed password.
Hash string
// Whether the user is an admin, i.e. allowed to do everything.
Admin bool
// Map of database name to granted privilege.
// 针对不同的database的privilege都存在这个map中
Privileges map[string]influxql.Privilege
}
func (ui *UserInfo) AuthorizeDatabase(privilege influxql.Privilege, database string) bool { if ui.Admin || privilege == influxql.NoPrivileges { return true
}
p, ok := ui.Privileges[database] // 查Privileges这个map
return ok && (p == privilege || p == influxql.AllPrivileges)
}写语句权限验证
srv.Handler.WriteAuthorizer = meta.NewWriteAuthorizer(s.MetaClient),创建了写权限验证对象具体实现
WriteAuthorizer(在 services/meta/write_authorizer.go中), 实现比较简单, 最终也是调用UserInfo.AuthorizeDatabase来验证
// WriteAuthorizer determines whether a user is authorized to write to a given database.type WriteAuthorizer struct {
Client *Client
} // AuthorizeWrite returns nil if the user has permission to write to the database.func (a WriteAuthorizer) AuthorizeWrite(username, database string) error {
u, err := a.Client.User(username) if err != nil || u == nil || !u.AuthorizeDatabase(influxql.WritePrivilege, database) { return &ErrAuthorize{
Database: database,
Message: fmt.Sprintf("%s not authorized to write to %s", username, database),
}
} return nil}Open权限验证
不需要授权验证的情况,Influxdb实现了
openAuthorizer, 它同样实现了Authorizer interface
// OpenAuthorizer is the Authorizer used when authorization is disabled.// It allows all operations.type openAuthorizer struct{} // OpenAuthorizer can be shared by all goroutines.var OpenAuthorizer = openAuthorizer{}
作者:扫帚的影子
链接:https://www.jianshu.com/p/472e743c2b4e
共同学习,写下你的评论
评论加载中...
作者其他优质文章
