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

token to db

parent 3beb8203
No related branches found
No related tags found
No related merge requests found
Showing with 118 additions and 47 deletions
......@@ -14,8 +14,8 @@ type Auth struct {
authJWT utils.Auth
}
func NewAuth(authUser,authAdmin,authJWT utils.Auth) *Auth {
return &Auth{authUser,authAdmin,authJWT}
func NewAuth(authUser, authAdmin, authJWT utils.Auth) *Auth {
return &Auth{authUser, authAdmin, authJWT}
}
func (auth *Auth) AdminAuth() utils.Auth {
......@@ -31,7 +31,7 @@ func (auth *Auth) JWTAuth() utils.Auth {
}
func subjectFromRequest(request structs.IssueTokenRequest) string {
for key,value := range request.Subject {
for key, value := range request.Subject {
switch key {
case "beamline":
return utils.SubjectFromBeamline(value)
......@@ -44,10 +44,10 @@ func subjectFromRequest(request structs.IssueTokenRequest) string {
return ""
}
func (auth *Auth) PrepareAccessToken(request structs.IssueTokenRequest, userToken bool) (string, error) {
var claims utils.CustomClaims
func (auth *Auth) PrepareAccessToken(request structs.IssueTokenRequest, userToken bool) (token string, claims *utils.CustomClaims, err error) {
var extraClaim structs.AccessTokenExtraClaim
claims = new(utils.CustomClaims)
claims.Subject = subjectFromRequest(request)
extraClaim.AccessTypes = request.AccessTypes
......@@ -57,15 +57,19 @@ func (auth *Auth) PrepareAccessToken(request structs.IssueTokenRequest, userToke
claims.Id = uid.String()
if userToken {
return auth.UserAuth().GenerateToken(&claims)
token, err = auth.UserAuth().GenerateToken(claims)
} else {
return auth.AdminAuth().GenerateToken(&claims)
token, err = auth.AdminAuth().GenerateToken(claims)
}
if err != nil {
return "", nil, err
}
return
}
func UserTokenResponce(request structs.IssueTokenRequest, token string) []byte {
expires := ""
if request.DaysValid>0 {
if request.DaysValid > 0 {
expires = time.Now().Add(time.Duration(request.DaysValid*24) * time.Hour).UTC().Format(time.RFC3339)
}
answer := structs.IssueTokenResponse{
......
......@@ -3,6 +3,8 @@
package cli
import (
"asapo_authorizer/database"
"asapo_authorizer/server"
"errors"
"flag"
"fmt"
......@@ -16,6 +18,8 @@ var flHelp bool
var outBuf io.Writer = os.Stdout
var db database.Agent
func printHelp(f *flag.FlagSet) bool {
if flHelp {
f.Usage()
......@@ -39,6 +43,11 @@ func DoCommand(name string, args []string) error {
method := methodVal.Interface().(func() error)
server.CreateDiscoveryService()
db = new(database.Mongodb)
server.InitDB(db)
defer db.Close()
return method()
}
......
......@@ -2,6 +2,7 @@ package cli
import (
"asapo_authorizer/authorization"
"asapo_authorizer/database"
"asapo_authorizer/server"
"asapo_common/structs"
"errors"
......@@ -19,24 +20,24 @@ type tokenFlags struct {
}
func userTokenRequest(flags tokenFlags) (request structs.IssueTokenRequest, err error) {
if (flags.Beamline=="" && flags.Beamtime=="") || (flags.Beamline!="" && flags.Beamtime!="") {
return request,errors.New("beamtime or beamline must be set")
if (flags.Beamline == "" && flags.Beamtime == "") || (flags.Beamline != "" && flags.Beamtime != "") {
return request, errors.New("beamtime or beamline must be set")
}
request.Subject = make(map[string]string,1)
if (flags.Beamline!="") {
request.Subject["beamline"]=flags.Beamline
request.Subject = make(map[string]string, 1)
if flags.Beamline != "" {
request.Subject["beamline"] = flags.Beamline
} else {
request.Subject["beamtimeId"]=flags.Beamtime
request.Subject["beamtimeId"] = flags.Beamtime
}
request.AccessTypes = strings.Split(flags.AccessType,",")
for _,at:=range request.AccessTypes {
if at != "read" && at != "write" && !(at== "writeraw" && request.Subject["beamline"]!="") {
if (request.Subject["beamline"]!="") {
return request,errors.New("access type must be read, write or writeraw")
request.AccessTypes = strings.Split(flags.AccessType, ",")
for _, at := range request.AccessTypes {
if at != "read" && at != "write" && !(at == "writeraw" && request.Subject["beamline"] != "") {
if request.Subject["beamline"] != "" {
return request, errors.New("access type must be read, write or writeraw")
} else {
return request,errors.New("access type must be read or write")
return request, errors.New("access type must be read or write")
}
}
......@@ -47,21 +48,20 @@ func userTokenRequest(flags tokenFlags) (request structs.IssueTokenRequest, err
return
}
func adminTokenRequest(flags tokenFlags) (request structs.IssueTokenRequest, err error) {
if flags.Beamline+flags.Beamtime!="" {
return request,errors.New("beamtime and beamline must not be set for admin token")
if flags.Beamline+flags.Beamtime != "" {
return request, errors.New("beamtime and beamline must not be set for admin token")
}
request.AccessTypes = strings.Split(flags.AccessType,",")
for _,at:=range request.AccessTypes {
if at!="create" && at!="revoke" && at!="list" {
return request,errors.New("access type must be create,revoke of list")
request.AccessTypes = strings.Split(flags.AccessType, ",")
for _, at := range request.AccessTypes {
if at != "create" && at != "revoke" && at != "list" {
return request, errors.New("access type must be create,revoke of list")
}
}
request.Subject = make(map[string]string,1)
request.Subject["user"]="admin"
request.Subject = make(map[string]string, 1)
request.Subject["user"] = "admin"
request.DaysValid = flags.DaysValid
return
......@@ -83,7 +83,17 @@ func (cmd *command) CommandCreate_token() (err error) {
return err
}
token, err := server.Auth.PrepareAccessToken(request,userToken)
token, claims, err := server.Auth.PrepareAccessToken(request, userToken)
if err != nil {
return err
}
record := database.TokenRecord{claims.Id, claims, token}
_, err = db.ProcessRequest(database.Request{
DbName: database.KAdminDb,
Collection: database.KTokens,
Op: "create_record",
}, &record)
if err != nil {
return err
}
......@@ -105,12 +115,11 @@ func getTokenRequest(flags tokenFlags) (request structs.IssueTokenRequest, userT
return structs.IssueTokenRequest{}, false, errors.New("wrong token type")
}
if err != nil {
return structs.IssueTokenRequest{},false, err
return structs.IssueTokenRequest{}, false, err
}
return request, userToken, err
}
func (cmd *command) parseTokenFlags(message_string string) (tokenFlags, error) {
var flags tokenFlags
......@@ -121,7 +130,6 @@ func (cmd *command) parseTokenFlags(message_string string) (tokenFlags, error) {
flagset.StringVar(&flags.AccessType, "access-types", "", "read/write/writeraw(beamline only) for user token")
flagset.IntVar(&flags.DaysValid, "duration-days", 0, "token duration (in days)")
flagset.Parse(cmd.args)
if printHelp(flagset) {
......@@ -129,10 +137,9 @@ func (cmd *command) parseTokenFlags(message_string string) (tokenFlags, error) {
}
if flags.Type == "" {
return flags, errors.New("secret file missed ")
return flags, errors.New("access types missing")
}
return flags, nil
}
......@@ -2,10 +2,12 @@ package cli
import (
"asapo_authorizer/authorization"
"asapo_authorizer/database"
"asapo_authorizer/server"
"asapo_common/structs"
"asapo_common/utils"
"encoding/json"
"github.com/stretchr/testify/mock"
"testing"
"bytes"
......@@ -41,13 +43,28 @@ var tokenTests = []struct {
func TestGenerateToken(t *testing.T) {
server.Auth = authorization.NewAuth(utils.NewJWTAuth("secret_user"),utils.NewJWTAuth("secret_admin"),utils.NewJWTAuth("secret"))
mock_db := new(database.MockedDatabase)
db = mock_db
for _, test := range tokenTests {
outBuf = new(bytes.Buffer)
if test.ok {
req := database.Request{
DbName: "asapo_admin",
Collection: "tokens",
Op: "create_record",
}
mock_db.On("ProcessRequest", req, mock.Anything).Return([]byte(""), nil)
}
err := test.cmd.CommandCreate_token()
if !test.ok {
assert.NotNil(t, err, test.msg)
continue
}
assert.Nil(t, err, test.msg)
var token structs.IssueTokenResponse
json.Unmarshal(outBuf.(*bytes.Buffer).Bytes(), &token)
......@@ -63,5 +80,9 @@ func TestGenerateToken(t *testing.T) {
} else {
assert.Empty(t, token.Expires, test.msg)
}
mock_db.AssertExpectations(t)
mock_db.ExpectedCalls = nil
mock_db.Calls = nil
}
}
......@@ -2,15 +2,24 @@ package database
import "asapo_common/utils"
const KAdminDb = "asapo_admin"
const KTokens = "tokens"
type Request struct {
DbName string
Collection string
Op string
ExtraParam string
}
type TokenRecord struct {
Id string `bson:"_id"`
*utils.CustomClaims
Token string
}
type Agent interface {
ProcessRequest(request Request) ([]byte, error)
ProcessRequest(request Request, extraParams ...interface{}) ([]byte, error)
Ping() error
Connect(string) error
Close()
......
......@@ -24,8 +24,7 @@ func (db *MockedDatabase) Ping() error {
return args.Error(0)
}
func (db *MockedDatabase) ProcessRequest(request Request) (answer []byte, err error) {
args := db.Called(request)
func (db *MockedDatabase) ProcessRequest(request Request, extraParams ...interface{}) (answer []byte, err error) {
args := db.Called(request,extraParams)
return args.Get(0).([]byte), args.Error(1)
}
......@@ -6,6 +6,7 @@ import (
"asapo_common/utils"
"context"
"errors"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"strings"
......@@ -107,7 +108,25 @@ func (db *Mongodb) checkDatabaseOperationPrerequisites(request Request) error {
return nil
}
func (db *Mongodb) ProcessRequest(request Request) (answer []byte, err error) {
func (db *Mongodb) createRecord(request Request, extra_params ...interface{}) ([]byte, error) {
if len(extra_params) != 1 {
return nil, errors.New("wrong number of parameters")
}
record := extra_params[0]
c := db.client.Database(request.DbName).Collection(request.Collection)
res, err := c.InsertOne(context.TODO(), record, options.InsertOne())
if err != nil {
return nil, err
}
newId, ok := res.InsertedID.(primitive.ObjectID)
if ok {
return []byte(newId.Hex()), nil
}
return nil, nil
}
func (db *Mongodb) ProcessRequest(request Request,extraParams ...interface{}) (answer []byte, err error) {
dbClientLock.RLock()
defer dbClientLock.RUnlock()
......@@ -116,6 +135,8 @@ func (db *Mongodb) ProcessRequest(request Request) (answer []byte, err error) {
}
switch request.Op {
case "create_record":
return db.createRecord(request, extraParams...)
}
return nil, errors.New("Wrong db operation: " + request.Op)
......
......@@ -45,7 +45,7 @@ func TestProcessRequestTestSuite(t *testing.T) {
func (suite *ProcessRequestTestSuite) TestProcessRequestWithConnectionError() {
req := database.Request{}
suite.mock_db.On("ProcessRequest", req).Return([]byte(""),
suite.mock_db.On("ProcessRequest", req,mock.Anything).Return([]byte(""),
&database.DBError{utils.StatusServiceUnavailable, ""})
ExpectReconnect(suite.mock_db)
......@@ -62,10 +62,9 @@ func (suite *ProcessRequestTestSuite) TestProcessRequestAddTokenToDb() {
DbName: "test",
Collection: "test",
Op: "test",
ExtraParam: "test",
}
suite.mock_db.On("ProcessRequest", req).Return([]byte("Hello"), nil)
suite.mock_db.On("ProcessRequest", req,mock.Anything).Return([]byte("Hello"), nil)
_,err := ProcessRequestInDb(req)
......
......@@ -62,7 +62,7 @@ func issueUserToken(w http.ResponseWriter, r *http.Request) {
return
}
token, err := Auth.PrepareAccessToken(request, true)
token, _, err := Auth.PrepareAccessToken(request, true)
if err != nil {
utils.WriteServerError(w, err, http.StatusInternalServerError)
return
......
......@@ -15,14 +15,16 @@ import (
"strconv"
)
func CreateDiscoveryService() {
discoveryService = discovery.CreateDiscoveryService(&http.Client{},"http://" + settings.DiscoveryServer)
}
func Start() {
mux := utils.NewRouter(listRoutes)
ldapClient = new(ldap_client.OpenLdapClient)
discoveryService = discovery.CreateDiscoveryService(&http.Client{},"http://" + settings.DiscoveryServer)
log.Info("Starting ASAPO Authorizer, version " + version.GetVersion())
CreateDiscoveryService()
err := InitDB(new(database.Mongodb))
if err != nil {
log.Error(err.Error())
......
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