maingate는 admin 계정으로 통일 또는 ApiToken

This commit is contained in:
2023-06-19 21:19:45 +09:00
parent 4bb25a1eff
commit 09328575ad
3 changed files with 91 additions and 113 deletions

View File

@ -86,7 +86,7 @@ func (caller apiCaller) isGlobalAdmin() bool {
return false
}
if _, ok := caller.admins[email.(string)]; ok {
if _, ok := caller.globalAdmins[email.(string)]; ok {
return true
}
@ -125,7 +125,7 @@ func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string
}
email = v.(string)
_, admin = caller.admins[email]
_, admin = caller.globalAdmins[email]
}
var output []*serviceDescription
@ -134,11 +134,9 @@ func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string
if admin {
output = append(output, desc)
editable = append(editable, desc.ServiceName)
} else if desc.isValidAPIUser("*", email) {
} else if caller.isAdminOrValidToken(email) {
output = append(output, desc)
if desc.isValidAPIUser("service", email) {
editable = append(editable, desc.ServiceName)
}
editable = append(editable, desc.ServiceName)
}
}
@ -149,60 +147,49 @@ func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string
return output, editable
}
func (caller apiCaller) isValidUser(service any, category string) (valid bool, admin bool) {
func (caller apiCaller) isAdmin(service any) bool {
if *noauth {
return true, true
return true
}
v, ok := caller.userinfo["email"]
if !ok {
logger.Println("isVaidUser failed. email is missing :", caller.userinfo)
return false, false
return false
}
email := v.(string)
if _, ok := caller.admins[email]; ok {
return true, true
if _, ok := caller.globalAdmins[email]; ok {
return true
}
svcdesc := caller.mg.services.get(service)
if svcdesc == nil {
logger.Println("isVaidUser failed. service is missing :", service)
return false, false
return false
}
return svcdesc.isValidAPIUser(category, email), false
return svcdesc.isAdmin(email)
}
func (caller apiCaller) isAdminOrValidToken(service any) bool {
if caller.isAdmin(service) {
return true
}
sh := caller.mg.services.get(service)
if sh == nil {
return false
}
return sh.isValidToken(caller.apiToken)
}
func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
if r.Method == "GET" {
hasAuth := caller.isGlobalAdmin()
var email string
if !*noauth {
v, ok := caller.userinfo["email"]
if !ok {
return nil
}
email = v.(string)
_, hasAuth = caller.admins[email]
}
servicename := r.FormValue("service")
sh := caller.mg.services.get(servicename)
if sh == nil {
w.WriteHeader(http.StatusBadRequest)
return nil
}
if !hasAuth {
if hasAuth = sh.isValidAPIUser("maintenance", email); !hasAuth {
hasAuth = sh.isValidAPIUser("service", email)
}
}
if !hasAuth {
w.WriteHeader(http.StatusBadRequest)
if !caller.isAdminOrValidToken(servicename) {
w.WriteHeader(http.StatusUnauthorized)
return nil
}
@ -228,6 +215,11 @@ func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
return nil
}
if !caller.isAdminOrValidToken(servicename) {
w.WriteHeader(http.StatusUnauthorized)
return nil
}
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
"service": servicename,
"key": key,
@ -309,14 +301,12 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
queryvals := r.URL.Query()
if r.Method == "GET" {
service := queryvals.Get("service")
if valid, _ := caller.isValidUser(service, "whitelist"); !valid {
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
return nil
}
if len(service) > 0 {
if !caller.isAdminOrValidToken(service) {
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusUnauthorized)
return nil
}
all, err := mg.mongoClient.FindAll(CollectionWhitelist, bson.M{
"service": service,
@ -344,9 +334,10 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
if err := json.Unmarshal(body, &member); err != nil {
return err
}
if valid, _ := caller.isValidUser(member.Service, "whitelist"); !valid {
if !caller.isAdminOrValidToken(member.Service) {
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusUnauthorized)
return nil
}
@ -391,16 +382,13 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
if r.Method == "GET" {
name := queryvals.Get("name")
if len(name) > 0 {
if valid, _ := caller.isValidUser(name, "*"); !valid {
if !caller.isAdminOrValidToken(name) {
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
return nil
}
if valid, admin := caller.isValidUser(name, "service"); valid || admin {
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
}
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
serptr := atomic.LoadPointer(&mg.services.get(name).serviceSerialized)
w.Write(*(*[]byte)(serptr))
} else {
@ -421,7 +409,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
w.WriteHeader(http.StatusBadRequest)
return nil
}
} else if valid, _ := caller.isValidUser(service.Id, "service"); !valid {
} else if !caller.isAdminOrValidToken(service.Id) {
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
return nil
@ -461,15 +449,11 @@ func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) e
if r.Method == "GET" {
name := queryvals.Get("name")
if len(name) > 0 {
if valid, _ := caller.isValidUser(name, "*"); !valid {
w.WriteHeader(http.StatusBadRequest)
if !caller.isAdminOrValidToken(name) {
w.WriteHeader(http.StatusUnauthorized)
return nil
}
if valid, admin := caller.isValidUser(name, "maintenance"); valid || admin {
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
}
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
serptr := atomic.LoadPointer(&mg.services.get(name).divisionsSerialized)
w.Write(*(*[]byte)(serptr))
} else {
@ -477,7 +461,7 @@ func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) e
}
} else if r.Method == "POST" {
servicename := queryvals.Get("name")
if valid, _ := caller.isValidUser(servicename, "service"); !valid {
if !caller.isAdminOrValidToken(servicename) {
logger.Println("maintenanceAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
return nil
@ -514,9 +498,9 @@ func (caller apiCaller) accountAPI(w http.ResponseWriter, r *http.Request) error
return nil
}
if valid, _ := caller.isValidUser(service, "account"); !valid {
if !caller.isAdminOrValidToken(service) {
logger.Println("accountAPI failed. not vaild user :", r.Method, caller.userinfo)
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusUnauthorized)
return nil
}
@ -641,9 +625,10 @@ func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error
var noauth = flag.Bool("noauth", false, "")
type apiCaller struct {
userinfo map[string]any
admins map[string]bool
mg *Maingate
userinfo map[string]any
globalAdmins map[string]bool
mg *Maingate
apiToken primitive.ObjectID
}
func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
@ -704,11 +689,24 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
}
}
apiToken := r.Header.Get("MG-X-API-TOKEN")
var apiTokenObj primitive.ObjectID
if len(apiToken) > 0 {
obj, err := primitive.ObjectIDFromHex(apiToken)
if err != nil {
logger.Error(err)
w.WriteHeader(http.StatusBadRequest)
return
}
apiTokenObj = obj
}
logger.Println("api call :", r.URL.Path, r.Method, r.URL.Query(), userinfo)
caller := apiCaller{
userinfo: userinfo,
admins: adminsptr.emails,
mg: mg,
userinfo: userinfo,
globalAdmins: adminsptr.emails,
mg: mg,
apiToken: apiTokenObj,
}
var err error

View File

@ -138,7 +138,7 @@ type serviceDescription struct {
ServiceDescriptionSummary `bson:",inline" json:",inline"`
Divisions map[string]*Division `bson:"divisions" json:"divisions"`
ServerApiTokens []primitive.ObjectID `bson:"api_tokens" json:"api_tokens"`
ApiUsers map[string][]string `bson:"api_users" json:"api_users"`
Admins []string `bson:"admins" json:"admins"`
auths *common.AuthCollection
wl whitelist
@ -150,13 +150,26 @@ type serviceDescription struct {
updateUserinfo func(info usertokeninfo) (bool, string, string)
getProviderInfo func(platform string, uid string) (string, string, error)
apiUsers unsafe.Pointer
admins unsafe.Pointer
divisionsForUsersSerialized unsafe.Pointer
divisionsSerialized unsafe.Pointer
serviceSerialized unsafe.Pointer
serviceSummarySerialized unsafe.Pointer
}
func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool {
if apiToken.IsZero() {
return false
}
for _, test := range sh.ServerApiTokens {
if test == apiToken {
return true
}
}
return false
}
func (sh *serviceDescription) readProfile(authtype string, id string, binfo string) (email string, err error) {
defer func() {
s := recover()
@ -254,25 +267,7 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
}
sh.wl.init(whites)
if len(sh.ApiUsers) == 0 {
sh.ApiUsers = map[string][]string{
"service": {},
"whitelist": {},
"account": {},
"maintenance": {},
}
}
parsedUsers := make(map[string]map[string]bool)
for cat, users := range sh.ApiUsers {
catusers := make(map[string]bool)
for _, user := range users {
catusers[user] = true
}
parsedUsers[cat] = catusers
}
sh.apiUsers = unsafe.Pointer(&parsedUsers)
sh.admins = unsafe.Pointer(&sh.Admins)
for _, keyid := range sh.ServerApiTokens {
mg.apiTokenToService.add(keyid.Hex(), sh.ServiceCode)
}
@ -283,7 +278,7 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
btsum, _ := json.Marshal(sh.ServiceDescriptionSummary)
atomic.StorePointer(&sh.serviceSummarySerialized, unsafe.Pointer(&btsum))
logger.Println("service is ready :", sh.ServiceName, sh.ServiceCode, sh.ApiUsers, string(divmarshaled))
logger.Println("service is ready :", sh.ServiceName, sh.ServiceCode, sh.Admins, string(divmarshaled))
return nil
}
@ -410,30 +405,15 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
logger.Println("link success :", r.URL.Query())
}
func (sh *serviceDescription) isValidAPIUser(category string, email string) bool {
ptr := atomic.LoadPointer(&sh.apiUsers)
catusers := *(*map[string]map[string]bool)(ptr)
func (sh *serviceDescription) isAdmin(email string) bool {
ptr := atomic.LoadPointer(&sh.admins)
admins := *(*[]string)(ptr)
if category == "*" {
for _, users := range catusers {
if _, ok := users[email]; ok {
return true
}
}
logger.Println("isValidAPIUser failed. email is not allowed :", category, email, catusers)
return false
}
if users, ok := catusers[category]; ok {
if _, ok := users[email]; ok {
for _, a := range admins {
if a == email {
return true
}
logger.Println("isValidAPIUser failed. email is not allowed :", category, email, users)
return false
}
logger.Println("isValidAPIUser failed. category is missing :", category)
return false
}

View File

@ -303,7 +303,7 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
if old := mg.services.get(data.Service.ServiceName); old != nil {
atomic.SwapPointer(&old.divisionsForUsersSerialized, data.Service.divisionsForUsersSerialized)
atomic.SwapPointer(&old.divisionsSerialized, data.Service.divisionsSerialized)
atomic.SwapPointer(&old.apiUsers, data.Service.apiUsers)
atomic.SwapPointer(&old.admins, data.Service.admins)
atomic.SwapPointer(&old.serviceSerialized, data.Service.serviceSerialized)
atomic.SwapPointer(&old.serviceSummarySerialized, data.Service.serviceSummarySerialized)