// AuthorizeRequest will add authorization header which contains a token before the request is sent func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error { var scopes []*scope var token string hasFrom := false from := req.URL.Query().Get("from") if len(from) != 0 { s := &scope{ Type: "repository", Name: from, Actions: []string{"pull"}, } scopes = append(scopes, s) // do not cache the token if "from" appears hasFrom = true } scopes = append(scopes, t.scope) expired := true cachedToken, cachedExpiredIn, cachedIssuedAt := t.getCachedToken() if len(cachedToken) != 0 && cachedExpiredIn != 0 && cachedIssuedAt != nil { expired = cachedIssuedAt.Add(time.Duration(cachedExpiredIn) * time.Second).Before(time.Now().UTC()) } if expired || hasFrom { scopeStrs := []string{} for _, scope := range scopes { scopeStrs = append(scopeStrs, scope.string()) } to, expiresIn, issuedAt, err := t.tg(params["realm"], params["service"], scopeStrs) if err != nil { return err } token = to if !hasFrom { t.updateCachedToken(to, expiresIn, issuedAt) log.Debug("add token to cache") } } else { token = cachedToken log.Debug("get token from cache") } req.Header.Add(http.CanonicalHeaderKey("Authorization"), fmt.Sprintf("Bearer %s", token)) log.Debugf("add token to request: %s %s", req.Method, req.URL.String()) return nil }
// Login authenticates user credentials based on setting. func Login(m models.AuthModel) (*models.User, error) { var authMode = os.Getenv("AUTH_MODE") 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) } return authenticator.Authenticate(m) }
// RefreshCatalogCache calls registry's API to get repository list and write it to cache. func RefreshCatalogCache() error { log.Debug("refreshing catalog cache...") if registryClient == nil { var err error registryClient, err = registry.NewRegistryWithUsername(endpoint, username) if err != nil { log.Errorf("error occurred while initializing registry client used by cache: %v", err) return err } } var err error rs, err := registryClient.Catalog() if err != nil { return err } repos := []string{} for _, repo := range rs { rc, ok := repositoryClients[repo] if !ok { rc, err = registry.NewRepositoryWithUsername(repo, endpoint, username) if err != nil { log.Errorf("error occurred while initializing repository client used by cache: %s %v", repo, err) continue } repositoryClients[repo] = rc } tags, err := rc.ListTag() if err != nil { log.Errorf("error occurred while list tag for %s: %v", repo, err) continue } if len(tags) != 0 { repos = append(repos, repo) log.Debugf("add %s to catalog cache", repo) } } Cache.Put(catalogKey, repos, 600*time.Second) return nil }
// 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) } }() }
// Authenticate checks user's credential agains LDAP based on basedn template and LDAP URL, // if the check is successful a dummy record will be insert 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) { ldapURL := os.Getenv("LDAP_URL") if ldapURL == "" { return nil, errors.New("Can not get any available LDAP_URL.") } log.Debug("ldapURL:", ldapURL) p := m.Principal for _, c := range metaChars { if strings.ContainsRune(p, c) { return nil, fmt.Errorf("the principal contains meta char: %q", c) } } ldap, err := openldap.Initialize(ldapURL) if err != nil { return nil, err } ldap.SetOption(openldap.LDAP_OPT_PROTOCOL_VERSION, openldap.LDAP_VERSION3) ldapBaseDn := os.Getenv("LDAP_BASE_DN") if ldapBaseDn == "" { return nil, errors.New("Can not get any available LDAP_BASE_DN.") } baseDn := fmt.Sprintf(ldapBaseDn, m.Principal) log.Debug("baseDn:", baseDn) err = ldap.Bind(baseDn, m.Password) if err != nil { return nil, err } defer ldap.Close() scope := openldap.LDAP_SCOPE_SUBTREE // LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE filter := "objectClass=*" attributes := []string{"mail"} result, err := ldap.SearchAll(baseDn, scope, filter, attributes) if err != nil { return nil, err } u := models.User{} if len(result.Entries()) == 1 { en := result.Entries()[0] for _, attr := range en.Attributes() { val := attr.Values()[0] if attr.Name() == "mail" { 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." userID, err := dao.Register(u) if err != nil { return nil, err } u.UserID = int(userID) } return &u, nil }
func (u *usernameTokenHandler) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) { token, expiresIn, issuedAt, err = token_util.GenTokenForUI(u.username, service, scopes) log.Debug("get token by calling GenTokenForUI directly") return }
func (s *standardTokenHandler) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) { u, err := url.Parse(realm) if err != nil { return } q := u.Query() q.Add("service", service) for _, scope := range scopes { q.Add("scope", scope) } u.RawQuery = q.Encode() r, err := http.NewRequest("GET", u.String(), nil) if err != nil { return } s.credential.AddAuthorization(r) resp, err := s.client.Do(r) if err != nil { return } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return } if resp.StatusCode != http.StatusOK { err = registry_errors.Error{ StatusCode: resp.StatusCode, StatusText: resp.Status, Message: string(b), } return } tk := struct { Token string `json:"token"` ExpiresIn int `json:"expires_in"` IssuedAt string `json:"issued_at"` }{} if err = json.Unmarshal(b, &tk); err != nil { return } token = tk.Token expiresIn = tk.ExpiresIn t, err := time.Parse(time.RFC3339, tk.IssuedAt) if err != nil { log.Errorf("error occurred while parsing issued_at: %v", err) err = nil } else { issuedAt = &t } log.Debug("get token from token server") return }