aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--weed/command/scaffold.go6
-rw-r--r--weed/security/guard.go24
-rw-r--r--weed/server/master_server.go6
-rw-r--r--weed/server/master_server_handlers.go16
-rw-r--r--weed/server/volume_server.go6
-rw-r--r--weed/server/volume_server_handlers.go20
-rw-r--r--weed/server/volume_server_handlers_read.go7
-rw-r--r--weed/server/volume_server_handlers_write.go4
8 files changed, 69 insertions, 20 deletions
diff --git a/weed/command/scaffold.go b/weed/command/scaffold.go
index 242bdddd7..08efc50eb 100644
--- a/weed/command/scaffold.go
+++ b/weed/command/scaffold.go
@@ -277,8 +277,14 @@ directory = "/" # destination directory
key = ""
expires_after_seconds = 10 # seconds
+# jwt for read is only supported with master+volume setup. Filer does not support this mode.
+[jwt.signing.read]
+key = ""
+expires_after_seconds = 10 # seconds
+
# all grpc tls authentications are mutual
# the values for the following ca, cert, and key are paths to the PERM files.
+# the host name is not checked, so the PERM files can be shared.
[grpc]
ca = ""
diff --git a/weed/security/guard.go b/weed/security/guard.go
index 5d25d8327..17fe2ea9e 100644
--- a/weed/security/guard.go
+++ b/weed/security/guard.go
@@ -41,21 +41,29 @@ https://github.com/pkieltyka/jwtauth/blob/master/jwtauth.go
*/
type Guard struct {
- whiteList []string
- SigningKey SigningKey
- ExpiresAfterSec int
+ whiteList []string
+ SigningKey SigningKey
+ ExpiresAfterSec int
+ ReadSigningKey SigningKey
+ ReadExpiresAfterSec int
- isActive bool
+ isWriteActive bool
}
-func NewGuard(whiteList []string, signingKey string, expiresAfterSec int) *Guard {
- g := &Guard{whiteList: whiteList, SigningKey: SigningKey(signingKey), ExpiresAfterSec: expiresAfterSec}
- g.isActive = len(g.whiteList) != 0 || len(g.SigningKey) != 0
+func NewGuard(whiteList []string, signingKey string, expiresAfterSec int, readSigningKey string, readExpiresAfterSec int) *Guard {
+ g := &Guard{
+ whiteList: whiteList,
+ SigningKey: SigningKey(signingKey),
+ ExpiresAfterSec: expiresAfterSec,
+ ReadSigningKey: SigningKey(readSigningKey),
+ ReadExpiresAfterSec: readExpiresAfterSec,
+ }
+ g.isWriteActive = len(g.whiteList) != 0 || len(g.SigningKey) != 0
return g
}
func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
- if !g.isActive {
+ if !g.isWriteActive {
//if no security needed, just skip all checking
return f
}
diff --git a/weed/server/master_server.go b/weed/server/master_server.go
index 8a51dc828..0076ed1f1 100644
--- a/weed/server/master_server.go
+++ b/weed/server/master_server.go
@@ -63,6 +63,10 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
v.SetDefault("jwt.signing.expires_after_seconds", 10)
expiresAfterSec := v.GetInt("jwt.signing.expires_after_seconds")
+ readSigningKey := v.GetString("jwt.signing.read.key")
+ v.SetDefault("jwt.signing.read.expires_after_seconds", 60)
+ readExpiresAfterSec := v.GetInt("jwt.signing.read.expires_after_seconds")
+
var preallocateSize int64
if preallocate {
preallocateSize = int64(volumeSizeLimitMB) * (1 << 20)
@@ -83,7 +87,7 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
ms.vg = topology.NewDefaultVolumeGrowth()
glog.V(0).Infoln("Volume Size Limit is", volumeSizeLimitMB, "MB")
- ms.guard = security.NewGuard(whiteList, signingKey, expiresAfterSec)
+ ms.guard = security.NewGuard(whiteList, signingKey, expiresAfterSec, readSigningKey, readExpiresAfterSec)
if !disableHttp {
handleStaticResources2(r)
diff --git a/weed/server/master_server_handlers.go b/weed/server/master_server_handlers.go
index 1c5b11565..5c7ff41cf 100644
--- a/weed/server/master_server_handlers.go
+++ b/weed/server/master_server_handlers.go
@@ -67,7 +67,9 @@ func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request)
if location.Error != "" {
httpStatus = http.StatusNotFound
} else {
- ms.maybeAddJwtAuthorization(w, fileId)
+ forRead := r.FormValue("read")
+ isRead := forRead == "yes"
+ ms.maybeAddJwtAuthorization(w, fileId, !isRead)
}
writeJsonQuiet(w, r, httpStatus, location)
}
@@ -102,17 +104,23 @@ func (ms *MasterServer) dirAssignHandler(w http.ResponseWriter, r *http.Request)
}
fid, count, dn, err := ms.Topo.PickForWrite(requestedCount, option)
if err == nil {
- ms.maybeAddJwtAuthorization(w, fid)
+ ms.maybeAddJwtAuthorization(w, fid, true)
writeJsonQuiet(w, r, http.StatusOK, operation.AssignResult{Fid: fid, Url: dn.Url(), PublicUrl: dn.PublicUrl, Count: count})
} else {
writeJsonQuiet(w, r, http.StatusNotAcceptable, operation.AssignResult{Error: err.Error()})
}
}
-func (ms *MasterServer) maybeAddJwtAuthorization(w http.ResponseWriter, fileId string) {
- encodedJwt := security.GenJwt(ms.guard.SigningKey, ms.guard.ExpiresAfterSec, fileId)
+func (ms *MasterServer) maybeAddJwtAuthorization(w http.ResponseWriter, fileId string, isWrite bool) {
+ var encodedJwt security.EncodedJwt
+ if isWrite {
+ encodedJwt = security.GenJwt(ms.guard.SigningKey, ms.guard.ExpiresAfterSec, fileId)
+ } else {
+ encodedJwt = security.GenJwt(ms.guard.ReadSigningKey, ms.guard.ReadExpiresAfterSec, fileId)
+ }
if encodedJwt == "" {
return
}
+
w.Header().Set("Authorization", "BEARER "+string(encodedJwt))
}
diff --git a/weed/server/volume_server.go b/weed/server/volume_server.go
index fab2edac0..f0da20323 100644
--- a/weed/server/volume_server.go
+++ b/weed/server/volume_server.go
@@ -44,6 +44,10 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
expiresAfterSec := v.GetInt("jwt.signing.expires_after_seconds")
enableUiAccess := v.GetBool("access.ui")
+ readSigningKey := v.GetString("jwt.signing.read.key")
+ v.SetDefault("jwt.signing.read.expires_after_seconds", 60)
+ readExpiresAfterSec := v.GetInt("jwt.signing.read.expires_after_seconds")
+
vs := &VolumeServer{
pulseSeconds: pulseSeconds,
dataCenter: dataCenter,
@@ -57,7 +61,7 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
vs.SeedMasterNodes = masterNodes
vs.store = storage.NewStore(vs.grpcDialOption, port, ip, publicUrl, folders, maxCounts, vs.needleMapKind)
- vs.guard = security.NewGuard(whiteList, signingKey, expiresAfterSec)
+ vs.guard = security.NewGuard(whiteList, signingKey, expiresAfterSec, readSigningKey, readExpiresAfterSec)
handleStaticResources(adminMux)
if signingKey == "" || enableUiAccess {
diff --git a/weed/server/volume_server_handlers.go b/weed/server/volume_server_handlers.go
index d23c08290..4197582fd 100644
--- a/weed/server/volume_server_handlers.go
+++ b/weed/server/volume_server_handlers.go
@@ -49,10 +49,22 @@ func (vs *VolumeServer) publicReadOnlyHandler(w http.ResponseWriter, r *http.Req
}
}
-func (vs *VolumeServer) maybeCheckJwtAuthorization(r *http.Request, vid, fid string) bool {
+func (vs *VolumeServer) maybeCheckJwtAuthorization(r *http.Request, vid, fid string, isWrite bool) bool {
- if len(vs.guard.SigningKey) == 0 {
- return true
+ var signingKey security.SigningKey
+
+ if isWrite {
+ if len(vs.guard.SigningKey) == 0 {
+ return true
+ } else {
+ signingKey = vs.guard.SigningKey
+ }
+ }else {
+ if len(vs.guard.ReadSigningKey) == 0 {
+ return true
+ } else {
+ signingKey = vs.guard.ReadSigningKey
+ }
}
tokenStr := security.GetJwt(r)
@@ -61,7 +73,7 @@ func (vs *VolumeServer) maybeCheckJwtAuthorization(r *http.Request, vid, fid str
return false
}
- token, err := security.DecodeJwt(vs.guard.SigningKey, tokenStr)
+ token, err := security.DecodeJwt(signingKey, tokenStr)
if err != nil {
glog.V(1).Infof("jwt verification error from %s: %v", r.RemoteAddr, err)
return false
diff --git a/weed/server/volume_server_handlers_read.go b/weed/server/volume_server_handlers_read.go
index 9bc436239..d2aaa4e24 100644
--- a/weed/server/volume_server_handlers_read.go
+++ b/weed/server/volume_server_handlers_read.go
@@ -3,6 +3,7 @@ package weed_server
import (
"bytes"
"context"
+ "errors"
"io"
"mime"
"mime/multipart"
@@ -27,6 +28,12 @@ var fileNameEscaper = strings.NewReplacer("\\", "\\\\", "\"", "\\\"")
func (vs *VolumeServer) GetOrHeadHandler(w http.ResponseWriter, r *http.Request) {
n := new(needle.Needle)
vid, fid, filename, ext, _ := parseURLPath(r.URL.Path)
+
+ if !vs.maybeCheckJwtAuthorization(r, vid, fid, false) {
+ writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
+ return
+ }
+
volumeId, err := needle.NewVolumeId(vid)
if err != nil {
glog.V(2).Infoln("parsing error:", err, r.URL.Path)
diff --git a/weed/server/volume_server_handlers_write.go b/weed/server/volume_server_handlers_write.go
index 188d88ddf..7c0e08554 100644
--- a/weed/server/volume_server_handlers_write.go
+++ b/weed/server/volume_server_handlers_write.go
@@ -29,7 +29,7 @@ func (vs *VolumeServer) PostHandler(w http.ResponseWriter, r *http.Request) {
return
}
- if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
+ if !vs.maybeCheckJwtAuthorization(r, vid, fid, true) {
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
return
}
@@ -65,7 +65,7 @@ func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
volumeId, _ := needle.NewVolumeId(vid)
n.ParsePath(fid)
- if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
+ if !vs.maybeCheckJwtAuthorization(r, vid, fid, true) {
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
return
}