Skip to content
Snippets Groups Projects
Commit 30f8c432 authored by Sergey Yakubov's avatar Sergey Yakubov
Browse files

switch broker to JWT tokens

parent a6523936
No related branches found
No related tags found
No related merge requests found
Showing
with 85 additions and 53 deletions
...@@ -33,9 +33,9 @@ func subjectFromRequest(request TokenRequest) string { ...@@ -33,9 +33,9 @@ func subjectFromRequest(request TokenRequest) string {
for key,value := range request.Subject { for key,value := range request.Subject {
switch key { switch key {
case "beamline": case "beamline":
return "bl_" + value return utils.SubjectFromBeamline(value)
case "beamtimeId": case "beamtimeId":
return "bt_" + value return utils.SubjectFromBeamtime(value)
default: default:
return value return value
} }
......
...@@ -154,34 +154,24 @@ func needHostAuthorization(creds SourceCredentials) bool { ...@@ -154,34 +154,24 @@ func needHostAuthorization(creds SourceCredentials) bool {
} }
func checkToken(token string, subject_expect string) (accessType string, err error) { func checkToken(token string, subject_expect string) (accessType string, err error) {
claims,err := Auth.UserAuth().CheckAndGetContent(token) var extra_claim utils.AccessTokenExtraClaim
subject,err := Auth.UserAuth().CheckAndGetContent(token,&extra_claim)
if err!=nil { if err!=nil {
return "",err return "",err
} }
cclaims,ok:=claims.(*utils.CustomClaims) if subject!=subject_expect {
if !ok {
return "",errors.New("wrong token claims")
}
if cclaims.Subject!=subject_expect {
return "",errors.New("wrong token for "+subject_expect) return "",errors.New("wrong token for "+subject_expect)
} }
var extra_claim utils.AccessTokenExtraClaim
ecMap,ok:=cclaims.ExtraClaims.(map[string]interface{})
if !ok {
return "",errors.New("wrong token extra claims")
}
err = utils.MapToStruct(ecMap, &extra_claim)
return extra_claim.AccessType,err return extra_claim.AccessType,err
} }
func authorizeByToken(creds SourceCredentials) (accessType string, err error) { func authorizeByToken(creds SourceCredentials) (accessType string, err error) {
subject_expect:="" subject_expect:=""
if (creds.BeamtimeId != "auto") { if (creds.BeamtimeId != "auto") {
subject_expect = "bt_"+creds.BeamtimeId subject_expect = utils.SubjectFromBeamtime(creds.BeamtimeId)
} else { } else {
subject_expect = "bl_" + creds.Beamline subject_expect = utils.SubjectFromBeamline(creds.Beamline)
} }
return checkToken(creds.Token,subject_expect) return checkToken(creds.Token,subject_expect)
} }
......
...@@ -39,7 +39,7 @@ func folderTokenResponce(token string) []byte{ ...@@ -39,7 +39,7 @@ func folderTokenResponce(token string) []byte{
} }
func checkBeamtimeToken(request folderTokenRequest) error { func checkBeamtimeToken(request folderTokenRequest) error {
_,err := checkToken(request.Token,"bt_"+request.BeamtimeId) _,err := checkToken(request.Token,utils.SubjectFromBeamtime(request.BeamtimeId))
return err return err
} }
......
...@@ -58,7 +58,7 @@ func processRequest(w http.ResponseWriter, r *http.Request, op string, extra_par ...@@ -58,7 +58,7 @@ func processRequest(w http.ResponseWriter, r *http.Request, op string, extra_par
return return
} }
if err := testAuth(r, db_name); err != nil { if err := authorize(r, db_name); err != nil {
writeAuthAnswer(w, "get "+op, db_name, err.Error()) writeAuthAnswer(w, "get "+op, db_name, err.Error())
return return
} }
......
...@@ -26,8 +26,15 @@ const expectedStream = "stream" ...@@ -26,8 +26,15 @@ const expectedStream = "stream"
func prepareTestAuth() { func prepareTestAuth() {
expectedBeamtimeId = "beamtime_id" expectedBeamtimeId = "beamtime_id"
expectedDBName = expectedBeamtimeId + "_" + expectedSource expectedDBName = expectedBeamtimeId + "_" + expectedSource
auth = utils.NewHMACAuth("secret") auth = utils.NewJWTAuth("secret")
token, err := auth.GenerateToken(&expectedBeamtimeId)
var claims utils.CustomClaims
var extraClaim utils.AccessTokenExtraClaim
claims.Subject = utils.SubjectFromBeamtime(expectedBeamtimeId)
extraClaim.AccessType = "read"
claims.ExtraClaims = &extraClaim
token, err := auth.GenerateToken(&claims)
if err != nil { if err != nil {
panic(err) panic(err)
} }
...@@ -107,7 +114,7 @@ func TestProcessRequestTestSuite(t *testing.T) { ...@@ -107,7 +114,7 @@ func TestProcessRequestTestSuite(t *testing.T) {
} }
func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() { func (suite *ProcessRequestTestSuite) TestProcessRequestWithWrongToken() {
logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong token"))) logger.MockLog.On("Error", mock.MatchedBy(containsMatcher("wrong JWT token")))
w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken) w := doRequest("/database/" + expectedBeamtimeId + "/" + expectedSource + "/" + expectedStream + "/" + expectedGroupID + "/next" + suffixWithWrongToken)
......
...@@ -2,6 +2,7 @@ package server ...@@ -2,6 +2,7 @@ package server
import ( import (
"asapo_common/logger" "asapo_common/logger"
"asapo_common/utils"
"errors" "errors"
"net/http" "net/http"
"strconv" "strconv"
...@@ -43,18 +44,37 @@ func datasetRequested(r *http.Request) (bool,int) { ...@@ -43,18 +44,37 @@ func datasetRequested(r *http.Request) (bool,int) {
return valueTrue(r, "dataset"),valueInt(r,"minsize") return valueTrue(r, "dataset"),valueInt(r,"minsize")
} }
func testAuth(r *http.Request, beamtime_id string) error { func authorize(r *http.Request, beamtime_id string) error {
token_got := r.URL.Query().Get("token") token := r.URL.Query().Get("token")
if len(token_got) == 0 { if len(token) == 0 {
return errors.New("cannot extract token from request") return errors.New("cannot extract token from request")
} }
token_expect, _ := auth.GenerateToken(&beamtime_id) var extra_claim utils.AccessTokenExtraClaim
subject,err := auth.CheckAndGetContent(token,&extra_claim)
if err!=nil {
return err
}
if token_got != token_expect { err = checkSubject(subject, beamtime_id)
return errors.New("wrong token") if err != nil {
return err
} }
return checkAccessType(extra_claim)
}
func checkSubject(subject string, beamtime_id string) error {
if subject != utils.SubjectFromBeamtime(beamtime_id) {
return errors.New("wrong token subject")
}
return nil
}
func checkAccessType(extra_claim utils.AccessTokenExtraClaim) error {
if extra_claim.AccessType != "read" && extra_claim.AccessType != "write" {
return errors.New("wrong token access type")
}
return nil return nil
} }
...@@ -29,7 +29,7 @@ func createAuth() (utils.Auth, error) { ...@@ -29,7 +29,7 @@ func createAuth() (utils.Auth, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return utils.NewHMACAuth(secret), nil return utils.NewJWTAuth(secret), nil
} }
func ReadConfig(fname string) (log.Level, error) { func ReadConfig(fname string) (log.Level, error) {
......
...@@ -6,7 +6,6 @@ import ( ...@@ -6,7 +6,6 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"net/http" "net/http"
"net/url" "net/url"
...@@ -32,7 +31,15 @@ type Auth interface { ...@@ -32,7 +31,15 @@ type Auth interface {
GenerateToken(...interface{}) (string, error) GenerateToken(...interface{}) (string, error)
ProcessAuth(http.HandlerFunc, string) http.HandlerFunc ProcessAuth(http.HandlerFunc, string) http.HandlerFunc
Name() string Name() string
CheckAndGetContent(token string, payload ...interface{}) (interface{}, error) CheckAndGetContent(token string, extraClaims interface{}, payload ...interface{}) (string,error)
}
func SubjectFromBeamtime(bt string)string {
return "bt_"+bt
}
func SubjectFromBeamline(bl string)string {
return "bl_"+bl
} }
...@@ -154,14 +161,23 @@ func ProcessJWTAuth(fn http.HandlerFunc, key string) http.HandlerFunc { ...@@ -154,14 +161,23 @@ func ProcessJWTAuth(fn http.HandlerFunc, key string) http.HandlerFunc {
} }
} }
func (a *JWTAuth) CheckAndGetContent(token string, payload ...interface{}) (interface{}, error) { func (a *JWTAuth) CheckAndGetContent(token string, extraClaims interface{}, payload ...interface{}) (subject string,err error) {
// payload ignored // payload ignored
claims, ok := CheckJWTToken(token,a.Key) c, ok := CheckJWTToken(token,a.Key)
if !ok {
return "",errors.New("wrong JWT token")
}
claim,ok := c.(*CustomClaims)
if !ok { if !ok {
fmt.Println("hello ",token,a.Key) return "",errors.New("cannot get CustomClaims")
return nil,errors.New("wrong JWT token") }
subject = claim.Subject
if extraClaims!=nil {
err = MapToStruct(claim.ExtraClaims.(map[string]interface{}), extraClaims)
} }
return claims,nil return subject,err
} }
...@@ -262,20 +278,20 @@ func ProcessHMACAuth(fn http.HandlerFunc, payload, key string) http.HandlerFunc ...@@ -262,20 +278,20 @@ func ProcessHMACAuth(fn http.HandlerFunc, payload, key string) http.HandlerFunc
} }
} }
func (a *HMACAuth) CheckAndGetContent(token string, payload ...interface{}) (interface{}, error) { func (a *HMACAuth) CheckAndGetContent(token string, _ interface{}, payload ...interface{}) (string,error) {
if len(payload) != 1 { if len(payload) != 1 {
return nil, errors.New("wrong payload") return "",errors.New("wrong payload")
} }
value, ok := payload[0].(string) value, ok := payload[0].(string)
if !ok { if !ok {
return "", errors.New("wrong payload") return "",errors.New("wrong payload")
} }
ok = CheckHMACToken(token,value,a.Key) ok = CheckHMACToken(token,value,a.Key)
if !ok { if !ok {
return nil,errors.New("wrong HMAC token") return "",errors.New("wrong HMAC token")
} }
return nil,nil return value,nil
} }
......
...@@ -33,7 +33,7 @@ func TestGenerateJWTToken(t *testing.T) { ...@@ -33,7 +33,7 @@ func TestGenerateJWTToken(t *testing.T) {
} }
var HJWTAuthtests = []struct { var JWTAuthtests = []struct {
Mode string Mode string
Key string Key string
User string User string
...@@ -50,7 +50,7 @@ var HJWTAuthtests = []struct { ...@@ -50,7 +50,7 @@ var HJWTAuthtests = []struct {
} }
func TestProcessJWTAuth(t *testing.T) { func TestProcessJWTAuth(t *testing.T) {
for _, test := range HJWTAuthtests { for _, test := range JWTAuthtests {
req, _ := http.NewRequest("POST", "http://blabla", nil) req, _ := http.NewRequest("POST", "http://blabla", nil)
var claim JobClaim var claim JobClaim
......
...@@ -21,12 +21,12 @@ cp beamtime-metadata* beamline/p07/current/ ...@@ -21,12 +21,12 @@ cp beamtime-metadata* beamline/p07/current/
#tokens #tokens
AdminToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNvcGpyaXB0MzNlb2ZjbWJuZyIsInN1YiI6ImFkbWluIiwiRXh0cmFDbGFpbXMiOnsiQWNjZXNzVHlwZSI6ImNyZWF0ZSJ9fQ.uRjtGPaRpOlOfKroijHRgMDNaZHnXsVPf0JaJ1XMg7o AdminToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNvcGpyaXB0MzNlb2ZjbWJuZyIsInN1YiI6ImFkbWluIiwiRXh0cmFDbGFpbXMiOnsiQWNjZXNzVHlwZSI6ImNyZWF0ZSJ9fQ.uRjtGPaRpOlOfKroijHRgMDNaZHnXsVPf0JaJ1XMg7o
#curl -v --silent -H "Authorization: Bearer $AdminToken" --data '{"Subject": {"beamtimeId":"12345678"},"DaysValid":123,"AccessType":"read"}' 127.0.0.1:5007/admin/issue --stderr - | tee /dev/stderr | grep "bt_12345678" curl -v --silent -H "Authorization: Bearer $AdminToken" --data '{"Subject": {"beamtimeId":"12345678"},"DaysValid":123,"AccessType":"read"}' 127.0.0.1:5007/admin/issue --stderr - | tee /dev/stderr | grep "bt_12345678"
#curl -v --silent -H "Authorization: Bearer blabla" --data '{"Subject": {"beamtimeId":"12345678"},"DaysValid":123,"AccessType":"read"}' 127.0.0.1:5007/admin/issue --stderr - | tee /dev/stderr | grep "token does not match" curl -v --silent -H "Authorization: Bearer blabla" --data '{"Subject": {"beamtimeId":"12345678"},"DaysValid":123,"AccessType":"read"}' 127.0.0.1:5007/admin/issue --stderr - | tee /dev/stderr | grep "token does not match"
#curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - #| tee /dev/stderr | grep c20180508-000-COM20181 curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep c20180508-000-COM20181
#curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep p00 curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep p00
#curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep detector curl -v --silent --data '{"SourceCredentials":"processed%c20180508-000-COM20181%%detector%","OriginHost":"127.0.0.1:5555"}' 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep detector
token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNxZWpyaXB0MzUybHQxNjhyZyIsInN1YiI6ImJ0X2MyMDE4MDUwOC0wMDAtQ09NMjAxODEiLCJFeHRyYUNsYWltcyI6eyJBY2Nlc3NUeXBlIjoicmVhZCJ9fQ.MDuQa_f0yOcn35xIgiCfoVVT56oTQ5tSiuKu9VqO_tE #token for c20180508-000-COM20181 token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNxZWpyaXB0MzUybHQxNjhyZyIsInN1YiI6ImJ0X2MyMDE4MDUwOC0wMDAtQ09NMjAxODEiLCJFeHRyYUNsYWltcyI6eyJBY2Nlc3NUeXBlIjoicmVhZCJ9fQ.MDuQa_f0yOcn35xIgiCfoVVT56oTQ5tSiuKu9VqO_tE #token for c20180508-000-COM20181
...@@ -49,12 +49,10 @@ curl -v --silent --data "{\"SourceCredentials\":\"raw%auto%p07%detector%$token\" ...@@ -49,12 +49,10 @@ curl -v --silent --data "{\"SourceCredentials\":\"raw%auto%p07%detector%$token\"
curl -v --silent --data "{\"SourceCredentials\":\"raw%auto%p07%detector%$token\",\"OriginHost\":\"127.0.0.1:5007\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep /asap3/petra3/gpfs/p07/2020/data/11111111 curl -v --silent --data "{\"SourceCredentials\":\"raw%auto%p07%detector%$token\",\"OriginHost\":\"127.0.0.1:5007\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep /asap3/petra3/gpfs/p07/2020/data/11111111
#read access #read access
curl -v --silent --data "{\"SourceCredentials\":\"processed%auto%p07%detector%$token\",\"OriginHost\":\"bla\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep read curl -v --silent --data "{\"SourceCredentials\":\"processed%auto%p07%detector%$token\",\"OriginHost\":\"bla\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep read
#write access #write access
token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNxcmFyaXB0MzVjcWpuMmUxZyIsInN1YiI6ImJsX3AwNyIsIkV4dHJhQ2xhaW1zIjp7IkFjY2Vzc1R5cGUiOiJyZWFkIn19.KQFj3hOJRpc7hPqwJyYmnQ31IrR1zSz4EifUuulmP5E # for beamlne p07, write access token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTQ4MG1yaXB0Mzc2Z2xvNWo3MCIsInN1YiI6ImJsX3AwNyIsIkV4dHJhQ2xhaW1zIjp7IkFjY2Vzc1R5cGUiOiJ3cml0ZSJ9fQ.8e4Xo1w-ICJzKjOwj2sGtpVfGppSGgPHv1yPLJwsdSA # for beamlne p07, write access
curl -v --silent --data "{\"SourceCredentials\":\"processed%auto%p07%detector%$token\",\"OriginHost\":\"bla\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep write curl -v --silent --data "{\"SourceCredentials\":\"processed%auto%p07%detector%$token\",\"OriginHost\":\"bla\"}" 127.0.0.1:5007/authorize --stderr - | tee /dev/stderr | grep write
rm -rf asap3 beamline rm -rf asap3 beamline
\ No newline at end of file
...@@ -15,7 +15,8 @@ C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"processed%%c20180 ...@@ -15,7 +15,8 @@ C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"processed%%c20180
C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"raw%%c20180508-000-COM20181%%%%detector%%wrong\",\"OriginHost\":\"127.0.0.1:5555\"}" 127.0.0.1:5007/authorize --stderr - | findstr 401 || goto :error C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"raw%%c20180508-000-COM20181%%%%detector%%wrong\",\"OriginHost\":\"127.0.0.1:5555\"}" 127.0.0.1:5007/authorize --stderr - | findstr 401 || goto :error
C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"raw%%auto%%p07%%detector%%-pZmisCNjAbjT2gFBKs3OB2kNOU79SNsfHud0bV8gS4=\",\"OriginHost\":\"127.0.0.1:5555\"}" 127.0.0.1:5007/authorize --stderr - | findstr 11111111 || goto :error set token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTNxcmFyaXB0MzVjcWpuMmUxZyIsInN1YiI6ImJsX3AwNyIsIkV4dHJhQ2xhaW1zIjp7IkFjY2Vzc1R5cGUiOiJyZWFkIn19.KQFj3hOJRpc7hPqwJyYmnQ31IrR1zSz4EifUuulmP5E"
C:\Curl\curl.exe -v --silent --data "{\"SourceCredentials\":\"raw%%auto%%p07%%detector%%%token%\",\"OriginHost\":\"127.0.0.1:5555\"}" 127.0.0.1:5007/authorize --stderr - | findstr 11111111 || goto :error
goto :clean goto :clean
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment