如何使用Thrift处理身份验证和授权?

19

我正在开发一个使用Thrift的系统。我希望检查客户端身份并对操作进行 ACL 授权。Thrift 是否提供任何支持?

3个回答

13

直接来说是不行的。唯一的方法是有一个身份验证方法,在服务器上创建一个(临时)密钥,然后更改所有的方法,使第一个参数成为此密钥,并且它们都会额外引发未经身份验证的错误。例如:

exception NotAuthorisedException {
    1: string errorMessage,
}

exception AuthTimeoutException {
    1: string errorMessage,
}

service MyAuthService {
    string authenticate( 1:string user, 2:string pass )
        throws ( 1:NotAuthorisedException e ),

    string mymethod( 1:string authstring, 2:string otherargs, ... )
        throws ( 1:AuthTimeoutException e, ... ),
}
我们使用这种方法,将我们的密钥保存到一个安全的memcached实例中,并且设置了30分钟的超时时间以保持一切“快速响应”。当客户端收到AuthTimeoutException异常时,我们期望客户端重新进行授权并重试,并且我们还有一些防火墙规则来防止暴力攻击。

2
@JensG 不,你需要以加密格式发送密码并在服务器端检查该编码字符串。Bcrypt非常适合此操作,因为通过网络发送的字符串可能与存储的字符串不完全匹配,但使用bcrypt算法进行检查仍然可以验证。 - Phillip B Oldham
如果是这种情况,您将不会发送明文密码,但如果攻击者能够读取哈希密码,则可以重放认证调用并访问您的服务。 - cjungel
2
可以使用SSL来保护通信安全。http://www.doublecloud.org/2014/01/securing-thrift-traffic-uncommon-but-important-use-case/ 描述了如何创建服务器密钥对,并在客户端中使用证书加密流量。这种机制应该提供了一个安全的通道,您可以按照答案中所述实现自定义身份验证/授权。 - cjungel

3

像授权和权限这样的任务并不被视为 Thrift 的一部分,主要是因为这些事情(通常)更与应用程序逻辑相关,而不是一般的 RPC/序列化概念。目前 Thrift 唯一支持的是 TSASLTransport。我个人对它不能说太多,只是因为我从未感到需要使用它。

另一个选择可能是利用 THeaderTransport,但遗憾的是,在撰写本文时,它仅在 C++ 中实现。因此,如果您计划将其与其他语言一起使用,您可能需要投入一些额外的工作。不用说,我们欢迎贡献...


0
有点晚了(我猜非常晚),但是我几年前修改了Thrift源代码来实现这个功能。刚刚提交了一个带有补丁的工单https://issues.apache.org/jira/browse/THRIFT-4221
可以看一下那个工单。基本上,建议添加一个“BeforeAction”钩子来实现这一点。
以下是Golang生成的示例差异。
+       // Called before any other action is called
+       BeforeAction(serviceName string, actionName string, args map[string]interface{}) (err error)
+       // Called if an action returned an error
+       ProcessError(err error) error
 }

 type MyServiceClient struct {
@@ -391,7 +395,12 @@ func (p *myServiceProcessorMyMethod) Process(seqId int32, iprot, oprot thrift.TP
        result := MyServiceMyMethodResult{}
        var retval string
        var err2 error
-       if retval, err2 = p.handler.MyMethod(args.AuthString, args.OtherArgs_); err2 != nil {
+       err2 = p.handler.BeforeAction("MyService", "MyMethod", map[string]interface{}{"AuthString": args.AuthString, "OtherArgs_": args.OtherArgs_})
+       if err2 == nil {
+               retval, err2 = p.handler.MyMethod(args.AuthString, args.OtherArgs_)
+       }
+       if err2 != nil {
+               err2 = p.handler.ProcessError(err2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接