// GetUserIDForRequest tries to get user ID from basic auth header and session. // It returns the user ID, whether need further verification(when the id is from session) and if the action is successful func (b *BaseAPI) GetUserIDForRequest() (int, bool, bool) { 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 { // User login successfully no further check required. return user.UserID, false, true } } sessionUserID, ok := b.GetSession("userId").(int) if ok { // The ID is from session return sessionUserID, true, true } log.Debug("No valid user id in session.") return 0, false, false }
// RefreshCatalogCache calls registry's API to get repository list and write it to cache. func RefreshCatalogCache() error { log.Debug("refreshing catalog cache...") repos, err := getAllRepositories() if err != nil { return err } Cache.Put(catalogKey, repos, 600*time.Second) return nil }
// Login authenticates user credentials based on setting. func Login(m models.AuthModel) (*models.User, error) { var authMode = config.AuthMode() if authMode == "" || m.Principal == "admin" { authMode = "db_auth" } log.Debug("Current AUTH_MODE is ", authMode) authenticator, ok := registry[authMode] if !ok { return nil, fmt.Errorf("Unrecognized auth_mode: %s", authMode) } if lock.IsLocked(m.Principal) { log.Debugf("%s is locked due to login failure, login failed", m.Principal) return nil, nil } user, err := authenticator.Authenticate(m) if user == nil && err == nil { log.Debugf("Login failed, locking %s, and sleep for %v", m.Principal, frozenTime) lock.Lock(m.Principal) time.Sleep(frozenTime) } return user, err }
// Delete ... func (ra *RepositoryAPI) Delete() { repoName := ra.GetString("repo_name") if len(repoName) == 0 { ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") } projectName, _ := utils.ParseRepository(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 == nil { ra.CustomAbort(http.StatusNotFound, fmt.Sprintf("project %s not found", projectName)) } 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 { if regErr.StatusCode != http.StatusNotFound { ra.CustomAbort(regErr.StatusCode, regErr.Detail) } } else { log.Errorf("error occurred while deleting tag %s:%s: %v", repoName, t, 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) } exist, err := repositoryExist(repoName, rc) if err != nil { log.Errorf("failed to check the existence of repository %s: %v", repoName, err) ra.CustomAbort(http.StatusInternalServerError, "") } if !exist { if err = dao.DeleteRepository(repoName); err != nil { log.Errorf("failed to delete repository %s: %v", repoName, err) ra.CustomAbort(http.StatusInternalServerError, "") } } go func() { log.Debug("refreshing catalog cache") if err := cache.RefreshCatalogCache(); err != nil { log.Errorf("error occurred while refresh catalog cache: %v", err) } }() }
// Authenticate checks user's credential against LDAP based on basedn template and LDAP URL, // if the check is successful a dummy record will be inserted into DB, such that this user can // be associated to other entities in the system. func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) { p := m.Principal for _, c := range metaChars { if strings.ContainsRune(p, c) { return nil, fmt.Errorf("the principal contains meta char: %q", c) } } ldapURL := config.LDAP().URL if ldapURL == "" { return nil, errors.New("can not get any available LDAP_URL") } log.Debug("ldapURL:", ldapURL) ldap, err := openldap.Initialize(ldapURL) if err != nil { return nil, err } ldap.SetOption(openldap.LDAP_OPT_PROTOCOL_VERSION, openldap.LDAP_VERSION3) ldapBaseDn := config.LDAP().BaseDn if ldapBaseDn == "" { return nil, errors.New("can not get any available LDAP_BASE_DN") } log.Debug("baseDn:", ldapBaseDn) ldapSearchDn := config.LDAP().SearchDn if ldapSearchDn != "" { log.Debug("Search DN: ", ldapSearchDn) ldapSearchPwd := config.LDAP().SearchPwd err = ldap.Bind(ldapSearchDn, ldapSearchPwd) if err != nil { log.Debug("Bind search dn error", err) return nil, err } } attrName := config.LDAP().UID filter := config.LDAP().Filter if filter != "" { filter = "(&" + filter + "(" + attrName + "=" + m.Principal + "))" } else { filter = "(" + attrName + "=" + m.Principal + ")" } log.Debug("one or more filter", filter) ldapScope := config.LDAP().Scope var scope int if ldapScope == "1" { scope = openldap.LDAP_SCOPE_BASE } else if ldapScope == "2" { scope = openldap.LDAP_SCOPE_ONELEVEL } else { scope = openldap.LDAP_SCOPE_SUBTREE } attributes := []string{"uid", "cn", "mail", "email"} result, err := ldap.SearchAll(ldapBaseDn, scope, filter, attributes) if err != nil { return nil, err } if len(result.Entries()) == 0 { log.Warningf("Not found an entry.") return nil, nil } else if len(result.Entries()) != 1 { log.Warningf("Found more than one entry.") return nil, nil } en := result.Entries()[0] bindDN := en.Dn() log.Debug("found entry:", en) err = ldap.Bind(bindDN, m.Password) if err != nil { log.Debug("Bind user error", err) return nil, err } defer ldap.Close() u := models.User{} for _, attr := range en.Attributes() { val := attr.Values()[0] switch attr.Name() { case "uid": u.Realname = val case "cn": u.Realname = val case "mail": u.Email = val case "email": u.Email = val } } u.Username = m.Principal log.Debug("username:"******",email:", u.Email) exist, err := dao.UserExists(u, "username") if err != nil { return nil, err } if exist { currentUser, err := dao.GetUser(u) if err != nil { return nil, err } u.UserID = currentUser.UserID } else { u.Realname = m.Principal u.Password = "******" u.Comment = "registered from LDAP." if u.Email == "" { u.Email = u.Username + "@placeholder.com" } userID, err := dao.Register(u) if err != nil { return nil, err } u.UserID = int(userID) } return &u, nil }