Feat: sign http request / read running mode from config file

This commit is contained in:
HFO4
2019-12-23 13:27:18 +08:00
parent fd7b6e33c8
commit 90827b2441
13 changed files with 199 additions and 45 deletions

View File

@@ -2,7 +2,11 @@ package auth
import (
model "github.com/HFO4/cloudreve/models"
"github.com/HFO4/cloudreve/pkg/conf"
"github.com/HFO4/cloudreve/pkg/serializer"
"github.com/HFO4/cloudreve/pkg/util"
"io/ioutil"
"net/http"
"net/url"
)
@@ -22,6 +26,26 @@ type Auth interface {
Check(body string, sign string) error
}
// SignRequest 对PUT\POST等复杂HTTP请求签名如果请求Header中
// 包含 X-Policy 则此请求会被认定为上传请求只会对URI部分和
// Policy部分进行签名。其他请求则会对URI和Body部分进行签名。
func SignRequest(r *http.Request, expires int64) *http.Request {
var rawSignString string
if policy, ok := r.Header["X-Policy"]; ok {
rawSignString = serializer.NewRequestSignString(r.URL.Path, policy[0], "")
} else {
body, _ := ioutil.ReadAll(r.Body)
rawSignString = serializer.NewRequestSignString(r.URL.Path, "", string(body))
}
// 生成签名
sign := General.Sign(rawSignString, expires)
// 将签名加到请求Header中
r.Header["Authorization"] = []string{"Bearer " + sign}
return r
}
// SignURI 对URI进行签名,签名只针对Path部分query部分不做验证
func SignURI(uri string, expires int64) (*url.URL, error) {
base, err := url.Parse(uri)
@@ -52,9 +76,18 @@ func CheckURI(url *url.URL) error {
}
// Init 初始化通用鉴权器
// TODO slave模式下从配置文件获取
// TODO 测试
func Init() {
var secretKey string
if conf.SystemConfig.Mode == "master" {
secretKey = model.GetSettingByName("secret_key")
} else {
secretKey = conf.SystemConfig.SlaveSecret
if secretKey == "" {
util.Log().Panic("未指定 SlaveSecret请前往配置文件中指定")
}
}
General = HMACAuth{
SecretKey: []byte(model.GetSettingByName("secret_key")),
SecretKey: []byte(secretKey),
}
}

View File

@@ -3,6 +3,8 @@ package auth
import (
"github.com/HFO4/cloudreve/pkg/util"
"github.com/stretchr/testify/assert"
"net/http"
"strings"
"testing"
"time"
)
@@ -46,3 +48,25 @@ func TestCheckURI(t *testing.T) {
asserts.Error(CheckURI(sign))
}
}
func TestSignRequest(t *testing.T) {
asserts := assert.New(t)
General = HMACAuth{SecretKey: []byte(util.RandStringRunes(256))}
// 非上传请求
{
req, err := http.NewRequest("POST", "http://127.0.0.1/api/v3/upload", strings.NewReader("I am body."))
asserts.NoError(err)
req = SignRequest(req, 10)
asserts.NotEmpty(req.Header["Authorization"])
}
// 上传请求
{
req, err := http.NewRequest("POST", "http://127.0.0.1/api/v3/upload", strings.NewReader("I am body."))
asserts.NoError(err)
req.Header["X-Policy"] = []string{"I am Policy"}
req = SignRequest(req, 10)
asserts.NotEmpty(req.Header["Authorization"])
}
}

View File

@@ -18,8 +18,11 @@ type database struct {
// system 系统通用配置
type system struct {
Mode string `validate:"eq=master|eq=slave"`
Listen string `validate:"required"`
Debug bool
SessionSecret string
SlaveSecret string `validate:"omitempty,gte=64"`
}
// captcha 验证码配置
@@ -84,7 +87,7 @@ func Init(path string) {
for sectionName, sectionStruct := range sections {
err = mapSection(sectionName, sectionStruct)
if err != nil {
util.Log().Warning("配置文件 %s 分区解析失败: %s", sectionName, err)
util.Log().Panic("配置文件 %s 分区解析失败: %s", sectionName, err)
}
}

View File

@@ -16,7 +16,9 @@ var DatabaseConfig = &database{
// SystemConfig 系统公用配置
var SystemConfig = &system{
Debug: false,
Debug: false,
Mode: "master",
Listen: ":5000",
}
// CaptchaConfig 验证码配置

22
pkg/serializer/auth.go Normal file
View File

@@ -0,0 +1,22 @@
package serializer
import "encoding/json"
// RequestRawSign 待签名的HTTP请求
type RequestRawSign struct {
Path string
Policy string
Body string
}
// NewRequestSignString 返回JSON格式的待签名字符串
// TODO 测试
func NewRequestSignString(path, policy, body string) string {
req := RequestRawSign{
Path: path,
Policy: policy,
Body: body,
}
res, _ := json.Marshal(req)
return string(res)
}

View File

@@ -0,0 +1,13 @@
package serializer
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestNewRequestSignString(t *testing.T) {
asserts := assert.New(t)
sign := NewRequestSignString("1", "2", "3")
asserts.NotEmpty(sign)
}