func updateInitPassword(userID int, password string) error { queryUser := models.User{UserID: userID} user, err := dao.GetUser(queryUser) if err != nil { return fmt.Errorf("Failed to get user, userID: %d %v", userID, err) } if user == nil { return fmt.Errorf("User id: %d does not exist.", userID) } if user.Salt == "" { salt, err := dao.GenerateRandomString() if err != nil { return fmt.Errorf("Failed to generate salt for encrypting password, %v", err) } user.Salt = salt user.Password = password err = dao.ChangeUserPassword(*user) if err != nil { return fmt.Errorf("Failed to update user encrypted password, userID: %d, err: %v", userID, err) } log.Infof("User id: %d updated its encypted password successfully.", userID) } else { log.Infof("User id: %d already has its encrypted password.", userID) } return nil }
// FilterAccess modify the action list in access based on permission // determine if the request needs to be authenticated. func FilterAccess(username string, authenticated bool, a *token.ResourceActions) { if a.Type == "registry" && a.Name == "catalog" { log.Infof("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions) return } //clear action list to assign to new acess element after perm check. a.Actions = []string{} if a.Type == "repository" { if strings.Contains(a.Name, "/") { //Only check the permission when the requested image has a namespace, i.e. project projectName := a.Name[0:strings.LastIndex(a.Name, "/")] var permission string if authenticated { isAdmin, err := dao.IsAdminRole(username) if err != nil { log.Errorf("Error occurred in IsAdminRole: %v", err) } if isAdmin { exist, err := dao.ProjectExists(projectName) if err != nil { log.Errorf("Error occurred in CheckExistProject: %v", err) return } if exist { permission = "RWM" } else { permission = "" log.Infof("project %s does not exist, set empty permission for admin\n", projectName) } } else { permission, err = dao.GetPermission(username, projectName) if err != nil { log.Errorf("Error occurred in GetPermission: %v", err) return } } } if strings.Contains(permission, "W") { a.Actions = append(a.Actions, "push") } if strings.Contains(permission, "M") { a.Actions = append(a.Actions, "*") } if strings.Contains(permission, "R") || dao.IsProjectPublic(projectName) { a.Actions = append(a.Actions, "pull") } } } log.Infof("current access, type: %s, name:%s, actions:%v \n", a.Type, a.Name, a.Actions) }
// FilterAccessLog handles GET to /api/projects/{}/logs func (p *ProjectAPI) FilterAccessLog() { p.userID = p.ValidateUser() var filter models.AccessLog p.DecodeJSONReq(&filter) username := filter.Username keywords := filter.Keywords beginTime := time.Unix(filter.BeginTimestamp, 0) endTime := time.Unix(filter.EndTimestamp, 0) query := models.AccessLog{ProjectID: p.projectID, Username: "******" + username + "%", Keywords: keywords, BeginTime: beginTime, BeginTimestamp: filter.BeginTimestamp, EndTime: endTime, EndTimestamp: filter.EndTimestamp} log.Infof("Query AccessLog: begin: %v, end: %v, keywords: %s", query.BeginTime, query.EndTime, query.Keywords) accessLogList, err := dao.GetAccessLogs(query) if err != nil { log.Errorf("Error occurred in GetAccessLogs, error: %v", err) p.CustomAbort(http.StatusInternalServerError, "Internal error.") } p.Data["json"] = accessLogList p.ServeJSON() }
func init() { maxWorkersEnv := os.Getenv("MAX_JOB_WORKERS") maxWorkers64, err := strconv.ParseInt(maxWorkersEnv, 10, 32) maxJobWorkers = int(maxWorkers64) if err != nil { log.Warningf("Failed to parse max works setting, error: %v, the default value: %d will be used", err, defaultMaxWorkers) maxJobWorkers = defaultMaxWorkers } localRegURL = os.Getenv("REGISTRY_URL") if len(localRegURL) == 0 { localRegURL = "http://registry:5000" } localUIURL = os.Getenv("UI_URL") if len(localUIURL) == 0 { localUIURL = "http://ui" } logDir = os.Getenv("LOG_DIR") if len(logDir) == 0 { logDir = "/var/log" } f, err := os.Open(logDir) defer f.Close() if err != nil { panic(err) } finfo, err := f.Stat() if err != nil { panic(err) } if !finfo.IsDir() { panic(fmt.Sprintf("%s is not a direcotry", logDir)) } uiSecret = os.Getenv("UI_SECRET") if len(uiSecret) == 0 { panic("UI Secret is not set") } verifyRemoteCert = os.Getenv("VERIFY_REMOTE_CERT") if len(verifyRemoteCert) == 0 { verifyRemoteCert = "on" } configPath := os.Getenv("CONFIG_PATH") if len(configPath) != 0 { log.Infof("Config path: %s", configPath) beego.LoadAppConfig("ini", configPath) } log.Debugf("config: maxJobWorkers: %d", maxJobWorkers) log.Debugf("config: localUIURL: %s", localUIURL) log.Debugf("config: localRegURL: %s", localRegURL) log.Debugf("config: verifyRemoteCert: %s", verifyRemoteCert) log.Debugf("config: logDir: %s", logDir) log.Debugf("config: uiSecret: ******") }
func TestMain(m *testing.M) { dbHost := os.Getenv("DB_HOST") if len(dbHost) == 0 { log.Fatalf("environment variable DB_HOST is not set") } dbUser := os.Getenv("DB_USR") if len(dbUser) == 0 { log.Fatalf("environment variable DB_USR is not set") } dbPort := os.Getenv("DB_PORT") if len(dbPort) == 0 { log.Fatalf("environment variable DB_PORT is not set") } dbPassword := os.Getenv("DB_PWD") log.Infof("DB_HOST: %s, DB_USR: %s, DB_PORT: %s, DB_PWD: %s\n", dbHost, dbUser, dbPort, dbPassword) os.Setenv("MYSQL_HOST", dbHost) os.Setenv("MYSQL_PORT", dbPort) os.Setenv("MYSQL_USR", dbUser) os.Setenv("MYSQL_PWD", dbPassword) os.Setenv("AUTH_MODE", "db_auth") InitDB() clearUp(username) os.Exit(m.Run()) }
// ValidateUser checks if the request triggered by a valid user func (b *BaseAPI) ValidateUser() int { username, password, ok := b.Ctx.Request.BasicAuth() if ok { log.Infof("Requst with Basic Authentication header, username: %s", username) user, err := auth.Login(models.AuthModel{ Principal: username, Password: password, }) if err != nil { log.Errorf("Error while trying to login, username: %s, error: %v", username, err) user = nil } if user != nil { return user.UserID } } sessionUserID := b.GetSession("userId") if sessionUserID == nil { log.Warning("No user id in session, canceling request") b.CustomAbort(http.StatusUnauthorized, "") } userID := sessionUserID.(int) u, err := dao.GetUser(models.User{UserID: userID}) if err != nil { log.Errorf("Error occurred in GetUser, error: %v", err) b.CustomAbort(http.StatusInternalServerError, "Internal error.") } if u == nil { log.Warningf("User was deleted already, user id: %d, canceling request.", userID) b.CustomAbort(http.StatusUnauthorized, "") } return userID }
func init() { //conf/app.conf -> os.Getenv("config_path") configPath := os.Getenv("CONFIG_PATH") if len(configPath) != 0 { log.Infof("Config path: %s", configPath) beego.LoadAppConfig("ini", configPath) } beego.AddFuncMap("i18n", i18n.Tr) langs := strings.Split(beego.AppConfig.String("lang::types"), "|") names := strings.Split(beego.AppConfig.String("lang::names"), "|") supportLanguages = make(map[string]langType) langTypes = make([]*langType, 0, len(langs)) for i, lang := range langs { t := langType{ Lang: lang, Name: names[i], } langTypes = append(langTypes, &t) supportLanguages[lang] = t if err := i18n.SetMessage(lang, "static/i18n/"+"locale_"+lang+".ini"); err != nil { log.Errorf("Fail to set message file: %s", err.Error()) } } }
// Get handles GET request, it checks the http header for user credentials // and parse service and scope based on docker registry v2 standard, // checkes the permission agains local DB and generates jwt token. func (h *Handler) Get() { var username, password string request := h.Ctx.Request service := h.GetString("service") scopes := h.GetStrings("scope") access := GetResourceActions(scopes) log.Infof("request url: %v", request.URL.String()) if svc_utils.VerifySecret(request) { log.Debugf("Will grant all access as this request is from job service with legal secret.") username = "******" } else { username, password, _ = request.BasicAuth() authenticated := authenticate(username, password) if len(scopes) == 0 && !authenticated { log.Info("login request with invalid credentials") h.CustomAbort(http.StatusUnauthorized, "") } for _, a := range access { FilterAccess(username, authenticated, a) } } h.serveToken(username, service, access) }
// Register add different authenticators to registry map. func Register(name string, authenticator Authenticator) { if _, dup := registry[name]; dup { log.Infof("authenticator: %s has been registered", name) return } registry[name] = authenticator }
// UpdateEnablement changes the enablement of the policy func (pa *RepPolicyAPI) UpdateEnablement() { id := pa.GetIDFromURL() policy, err := dao.GetRepPolicy(id) if err != nil { log.Errorf("failed to get policy %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if policy == nil { pa.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound)) } e := enablementReq{} pa.DecodeJSONReq(&e) if e.Enabled != 0 && e.Enabled != 1 { pa.RenderError(http.StatusBadRequest, "invalid enabled value") return } if policy.Enabled == e.Enabled { return } if err := dao.UpdateRepPolicyEnablement(id, e.Enabled); err != nil { log.Errorf("Failed to update policy enablement in DB, error: %v", err) pa.RenderError(http.StatusInternalServerError, "Internal Error") return } if e.Enabled == 1 { go func() { if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil { log.Errorf("failed to trigger replication of %d: %v", id, err) } else { log.Infof("replication of %d triggered", id) } }() } else { go func() { if err := postReplicationAction(id, "stop"); err != nil { log.Errorf("failed to stop replication of %d: %v", id, err) } else { log.Infof("try to stop replication of %d", id) } }() } }
// TriggerReplicationByRepository triggers the replication according to the repository func TriggerReplicationByRepository(repository string, tags []string, operation string) { policies, err := GetPoliciesByRepository(repository) if err != nil { log.Errorf("failed to get policies for repository %s: %v", repository, err) return } for _, policy := range policies { if policy.Enabled == 0 { continue } if err := TriggerReplication(policy.ID, repository, tags, operation); err != nil { log.Errorf("failed to trigger replication of policy %d for %s: %v", policy.ID, repository, err) } else { log.Infof("replication of policy %d for %s triggered", policy.ID, repository) } } }
// PushBlob ... func (r *Repository) PushBlob(digest string, size int64, data []byte) error { exist, err := r.BlobExist(digest) if err != nil { return err } if exist { log.Infof("blob already exists, skip pushing: %s %s", r.Name, digest) return nil } location, _, err := r.initiateBlobUpload(r.Name) if err != nil { return err } return r.monolithicBlobUpload(location, digest, size, data) }
// Get handles GET request, it checks the http header for user credentials // and parse service and scope based on docker registry v2 standard, // checkes the permission agains local DB and generates jwt token. func (h *Handler) Get() { request := h.Ctx.Request log.Infof("request url: %v", request.URL.String()) username, password, _ := request.BasicAuth() authenticated := authenticate(username, password) service := h.GetString("service") scopes := h.GetStrings("scope") if len(scopes) == 0 && !authenticated { log.Info("login request with invalid credentials") h.CustomAbort(http.StatusUnauthorized, "") } access := GetResourceActions(scopes) for _, a := range access { FilterAccess(username, authenticated, a) } h.serveToken(username, service, access) }
// Delete ... func (ra *RepositoryAPI) Delete() { repoName := ra.GetString("repo_name") if len(repoName) == 0 { ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") } projectName := getProjectName(repoName) project, err := dao.GetProjectByName(projectName) if err != nil { log.Errorf("failed to get project %s: %v", projectName, err) ra.CustomAbort(http.StatusInternalServerError, "") } if project.Public == 0 { userID := ra.ValidateUser() if !hasProjectAdminRole(userID, project.ProjectID) { ra.CustomAbort(http.StatusForbidden, "") } } rc, err := ra.initRepositoryClient(repoName) if err != nil { log.Errorf("error occurred while initializing repository client for %s: %v", repoName, err) ra.CustomAbort(http.StatusInternalServerError, "internal error") } tags := []string{} tag := ra.GetString("tag") if len(tag) == 0 { tagList, err := rc.ListTag() if err != nil { if regErr, ok := err.(*registry_error.Error); ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail) } log.Errorf("error occurred while listing tags of %s: %v", repoName, err) ra.CustomAbort(http.StatusInternalServerError, "internal error") } // TODO remove the logic if the bug of registry is fixed if len(tagList) == 0 { ra.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound)) } tags = append(tags, tagList...) } else { tags = append(tags, tag) } user, _, ok := ra.Ctx.Request.BasicAuth() if !ok { user, err = ra.getUsername() if err != nil { log.Errorf("failed to get user: %v", err) } } for _, t := range tags { if err := rc.DeleteTag(t); err != nil { if regErr, ok := err.(*registry_error.Error); ok { ra.CustomAbort(regErr.StatusCode, regErr.Detail) } log.Errorf("error occurred while deleting tags of %s: %v", repoName, err) ra.CustomAbort(http.StatusInternalServerError, "internal error") } log.Infof("delete tag: %s %s", repoName, t) go TriggerReplicationByRepository(repoName, []string{t}, models.RepOpDelete) go func(tag string) { if err := dao.AccessLog(user, projectName, repoName, tag, "delete"); err != nil { log.Errorf("failed to add access log: %v", err) } }(t) } go func() { log.Debug("refreshing catalog cache") if err := cache.RefreshCatalogCache(); err != nil { log.Errorf("error occurred while refresh catalog cache: %v", err) } }() }
// Post creates a policy, and if it is enbled, the replication will be triggered right now. func (pa *RepPolicyAPI) Post() { policy := &models.RepPolicy{} pa.DecodeJSONReqAndValidate(policy) po, err := dao.GetRepPolicyByName(policy.Name) if err != nil { log.Errorf("failed to get policy %s: %v", policy.Name, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if po != nil { pa.CustomAbort(http.StatusConflict, "name is already used") } project, err := dao.GetProjectByID(policy.ProjectID) if err != nil { log.Errorf("failed to get project %d: %v", policy.ProjectID, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if project == nil { pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("project %d does not exist", policy.ProjectID)) } target, err := dao.GetRepTarget(policy.TargetID) if err != nil { log.Errorf("failed to get target %d: %v", policy.TargetID, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if target == nil { pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("target %d does not exist", policy.TargetID)) } policies, err := dao.GetRepPolicyByProjectAndTarget(policy.ProjectID, policy.TargetID) if err != nil { log.Errorf("failed to get policy [project ID: %d,targetID: %d]: %v", policy.ProjectID, policy.TargetID, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if len(policies) > 0 { pa.CustomAbort(http.StatusConflict, "policy already exists with the same project and target") } pid, err := dao.AddRepPolicy(*policy) if err != nil { log.Errorf("Failed to add policy to DB, error: %v", err) pa.RenderError(http.StatusInternalServerError, "Internal Error") return } if policy.Enabled == 1 { go func() { if err := TriggerReplication(pid, "", nil, models.RepOpTransfer); err != nil { log.Errorf("failed to trigger replication of %d: %v", pid, err) } else { log.Infof("replication of %d triggered", pid) } }() } pa.Redirect(http.StatusCreated, strconv.FormatInt(pid, 10)) }
// Put modifies name, description, target and enablement of policy func (pa *RepPolicyAPI) Put() { id := pa.GetIDFromURL() originalPolicy, err := dao.GetRepPolicy(id) if err != nil { log.Errorf("failed to get policy %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if originalPolicy == nil { pa.CustomAbort(http.StatusNotFound, http.StatusText(http.StatusNotFound)) } policy := &models.RepPolicy{} pa.DecodeJSONReq(policy) policy.ProjectID = originalPolicy.ProjectID pa.Validate(policy) // check duplicate name if policy.Name != originalPolicy.Name { po, err := dao.GetRepPolicyByName(policy.Name) if err != nil { log.Errorf("failed to get policy %s: %v", policy.Name, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if po != nil { pa.CustomAbort(http.StatusConflict, "name is already used") } } if policy.TargetID != originalPolicy.TargetID { //target of policy can not be modified when the policy is enabled if originalPolicy.Enabled == 1 { pa.CustomAbort(http.StatusBadRequest, "target of policy can not be modified when the policy is enabled") } // check the existance of target target, err := dao.GetRepTarget(policy.TargetID) if err != nil { log.Errorf("failed to get target %d: %v", policy.TargetID, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if target == nil { pa.CustomAbort(http.StatusBadRequest, fmt.Sprintf("target %d does not exist", policy.TargetID)) } // check duplicate policy with the same project and target policies, err := dao.GetRepPolicyByProjectAndTarget(policy.ProjectID, policy.TargetID) if err != nil { log.Errorf("failed to get policy [project ID: %d,targetID: %d]: %v", policy.ProjectID, policy.TargetID, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if len(policies) > 0 { pa.CustomAbort(http.StatusConflict, "policy already exists with the same project and target") } } policy.ID = id /* isTargetChanged := !(policy.TargetID == originalPolicy.TargetID) isEnablementChanged := !(policy.Enabled == policy.Enabled) var shouldStop, shouldTrigger bool // if target and enablement are not changed, do nothing if !isTargetChanged && !isEnablementChanged { shouldStop = false shouldTrigger = false } else if !isTargetChanged && isEnablementChanged { // target is not changed, but enablement is changed if policy.Enabled == 0 { shouldStop = true shouldTrigger = false } else { shouldStop = false shouldTrigger = true } } else if isTargetChanged && !isEnablementChanged { // target is changed, but enablement is not changed if policy.Enabled == 0 { // enablement is 0, do nothing shouldStop = false shouldTrigger = false } else { // enablement is 1, so stop original target's jobs // and trigger new target's jobs shouldStop = true shouldTrigger = true } } else { // both target and enablement are changed // enablement: 1 -> 0 if policy.Enabled == 0 { shouldStop = true shouldTrigger = false } else { shouldStop = false shouldTrigger = true } } if shouldStop { if err := postReplicationAction(id, "stop"); err != nil { log.Errorf("failed to stop replication of %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } log.Infof("replication of %d has been stopped", id) } if err = dao.UpdateRepPolicy(policy); err != nil { log.Errorf("failed to update policy %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if shouldTrigger { go func() { if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil { log.Errorf("failed to trigger replication of %d: %v", id, err) } else { log.Infof("replication of %d triggered", id) } }() } */ if err = dao.UpdateRepPolicy(policy); err != nil { log.Errorf("failed to update policy %d: %v", id, err) pa.CustomAbort(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) } if policy.Enabled != originalPolicy.Enabled && policy.Enabled == 1 { go func() { if err := TriggerReplication(id, "", nil, models.RepOpTransfer); err != nil { log.Errorf("failed to trigger replication of %d: %v", id, err) } else { log.Infof("replication of %d triggered", id) } }() } }