diff --git a/authorizer/src/asapo_authorizer/authorization/authorization.go b/authorizer/src/asapo_authorizer/authorization/authorization.go index 89cb04564244e16fa533333d389924f593ab7c0f..1c2894414556e7097babad574edfa078083dd240 100644 --- a/authorizer/src/asapo_authorizer/authorization/authorization.go +++ b/authorizer/src/asapo_authorizer/authorization/authorization.go @@ -33,9 +33,9 @@ func subjectFromRequest(request TokenRequest) string { for key,value := range request.Subject { switch key { case "beamline": - return "bl_" + value + return utils.SubjectFromBeamline(value) case "beamtimeId": - return "bt_" + value + return utils.SubjectFromBeamtime(value) default: return value } diff --git a/authorizer/src/asapo_authorizer/server/authorize.go b/authorizer/src/asapo_authorizer/server/authorize.go index 3aba607eaae956167809cca9d999ab935a9e727f..636a54c6fb8acc814a4aed5a036c7feeb4842954 100644 --- a/authorizer/src/asapo_authorizer/server/authorize.go +++ b/authorizer/src/asapo_authorizer/server/authorize.go @@ -154,34 +154,24 @@ func needHostAuthorization(creds SourceCredentials) bool { } 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 { return "",err } - cclaims,ok:=claims.(*utils.CustomClaims) - if !ok { - return "",errors.New("wrong token claims") - } - if cclaims.Subject!=subject_expect { + if subject!=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 } func authorizeByToken(creds SourceCredentials) (accessType string, err error) { subject_expect:="" if (creds.BeamtimeId != "auto") { - subject_expect = "bt_"+creds.BeamtimeId + subject_expect = utils.SubjectFromBeamtime(creds.BeamtimeId) } else { - subject_expect = "bl_" + creds.Beamline + subject_expect = utils.SubjectFromBeamline(creds.Beamline) } return checkToken(creds.Token,subject_expect) } diff --git a/authorizer/src/asapo_authorizer/server/folder_token.go b/authorizer/src/asapo_authorizer/server/folder_token.go index 6b2375fd86a57b3185841b612db64193dac410b9..b1c79b811049790df9d984a837e2c862f3f7db83 100644 --- a/authorizer/src/asapo_authorizer/server/folder_token.go +++ b/authorizer/src/asapo_authorizer/server/folder_token.go @@ -39,7 +39,7 @@ func folderTokenResponce(token string) []byte{ } func checkBeamtimeToken(request folderTokenRequest) error { - _,err := checkToken(request.Token,"bt_"+request.BeamtimeId) + _,err := checkToken(request.Token,utils.SubjectFromBeamtime(request.BeamtimeId)) return err } diff --git a/broker/src/asapo_broker/server/process_request.go b/broker/src/asapo_broker/server/process_request.go index 3e937b879ac297a709b962f6f5d96b597bb6d76a..7ab283d4409f38c23d840face63739a9fa84ec42 100644 --- a/broker/src/asapo_broker/server/process_request.go +++ b/broker/src/asapo_broker/server/process_request.go @@ -58,7 +58,7 @@ func processRequest(w http.ResponseWriter, r *http.Request, op string, extra_par 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()) return } diff --git a/broker/src/asapo_broker/server/process_request_test.go b/broker/src/asapo_broker/server/process_request_test.go index b4967924720e52f8a431937d207f216687601171..7c1f99209d3186fd98794ab9e302085d8748e3b6 100644 --- a/broker/src/asapo_broker/server/process_request_test.go +++ b/broker/src/asapo_broker/server/process_request_test.go @@ -26,8 +26,15 @@ const expectedStream = "stream" func prepareTestAuth() { expectedBeamtimeId = "beamtime_id" expectedDBName = expectedBeamtimeId + "_" + expectedSource - auth = utils.NewHMACAuth("secret") - token, err := auth.GenerateToken(&expectedBeamtimeId) + auth = utils.NewJWTAuth("secret") + + 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 { panic(err) } @@ -107,7 +114,7 @@ func TestProcessRequestTestSuite(t *testing.T) { } 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) diff --git a/broker/src/asapo_broker/server/request_common.go b/broker/src/asapo_broker/server/request_common.go index 28f2bc38d729c1cc14cafc6e696bdf71cfc9ccd8..0ba56384049c926ae3a4eb32093c87d5ff82f1fe 100644 --- a/broker/src/asapo_broker/server/request_common.go +++ b/broker/src/asapo_broker/server/request_common.go @@ -2,6 +2,7 @@ package server import ( "asapo_common/logger" + "asapo_common/utils" "errors" "net/http" "strconv" @@ -43,18 +44,37 @@ func datasetRequested(r *http.Request) (bool,int) { return valueTrue(r, "dataset"),valueInt(r,"minsize") } -func testAuth(r *http.Request, beamtime_id string) error { - token_got := r.URL.Query().Get("token") +func authorize(r *http.Request, beamtime_id string) error { + token := r.URL.Query().Get("token") - if len(token_got) == 0 { + if len(token) == 0 { 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 { - return errors.New("wrong token") + err = checkSubject(subject, beamtime_id) + 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 } diff --git a/broker/src/asapo_broker/server/server_nottested.go b/broker/src/asapo_broker/server/server_nottested.go index ffa4df68f9fab3e6fc40dbdbd68c66d8a43a4dc7..b1de8b98cfcf77a8150bf94be7c006ae0fa028b8 100644 --- a/broker/src/asapo_broker/server/server_nottested.go +++ b/broker/src/asapo_broker/server/server_nottested.go @@ -29,7 +29,7 @@ func createAuth() (utils.Auth, error) { if err != nil { return nil, err } - return utils.NewHMACAuth(secret), nil + return utils.NewJWTAuth(secret), nil } func ReadConfig(fname string) (log.Level, error) { diff --git a/common/go/src/asapo_common/utils/authorization.go b/common/go/src/asapo_common/utils/authorization.go index eeebc4f1f6eecc85537bb11c759bd6a54bfd4b30..724055db7abee35249e9722084b7c1d21d13f585 100644 --- a/common/go/src/asapo_common/utils/authorization.go +++ b/common/go/src/asapo_common/utils/authorization.go @@ -6,7 +6,6 @@ import ( "crypto/sha256" "encoding/base64" "errors" - "fmt" "github.com/dgrijalva/jwt-go" "net/http" "net/url" @@ -32,7 +31,15 @@ type Auth interface { GenerateToken(...interface{}) (string, error) ProcessAuth(http.HandlerFunc, string) http.HandlerFunc 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 { } } -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 - 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 { - fmt.Println("hello ",token,a.Key) - return nil,errors.New("wrong JWT token") + return "",errors.New("cannot get CustomClaims") + } + + 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 } } -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 { - return nil, errors.New("wrong payload") + return "",errors.New("wrong payload") } value, ok := payload[0].(string) if !ok { - return "", errors.New("wrong payload") + return "",errors.New("wrong payload") } ok = CheckHMACToken(token,value,a.Key) if !ok { - return nil,errors.New("wrong HMAC token") + return "",errors.New("wrong HMAC token") } - return nil,nil + return value,nil } diff --git a/common/go/src/asapo_common/utils/authorization_test.go b/common/go/src/asapo_common/utils/authorization_test.go index 147b6bfc272aad85549aeccedbfa7460767eece5..5a407330599738f690f350bdfe7c1001bf7ea782 100644 --- a/common/go/src/asapo_common/utils/authorization_test.go +++ b/common/go/src/asapo_common/utils/authorization_test.go @@ -33,7 +33,7 @@ func TestGenerateJWTToken(t *testing.T) { } -var HJWTAuthtests = []struct { +var JWTAuthtests = []struct { Mode string Key string User string @@ -50,7 +50,7 @@ var HJWTAuthtests = []struct { } func TestProcessJWTAuth(t *testing.T) { - for _, test := range HJWTAuthtests { + for _, test := range JWTAuthtests { req, _ := http.NewRequest("POST", "http://blabla", nil) var claim JobClaim diff --git a/tests/automatic/authorizer/check_authorize/check_linux.sh b/tests/automatic/authorizer/check_authorize/check_linux.sh index 68a517de390f6f0af8b539707bd1c97613b41dae..21d2561126a943f2002641d227dae9b62e350664 100644 --- a/tests/automatic/authorizer/check_authorize/check_linux.sh +++ b/tests/automatic/authorizer/check_authorize/check_linux.sh @@ -21,12 +21,12 @@ cp beamtime-metadata* beamline/p07/current/ #tokens 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 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 $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 --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 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 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 detector 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\" 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 -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 -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 - - rm -rf asap3 beamline \ No newline at end of file diff --git a/tests/automatic/authorizer/check_authorize/check_windows.bat b/tests/automatic/authorizer/check_authorize/check_windows.bat index c90cce0d6993493cea730a1cd5226ef6cc021018..64a02ff130fb865098dd7395b50314f59c5c5b6a 100644 --- a/tests/automatic/authorizer/check_authorize/check_windows.bat +++ b/tests/automatic/authorizer/check_authorize/check_windows.bat @@ -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%%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