Beispiel #1
0
// 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
}
Beispiel #2
0
// 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)
}
Beispiel #3
0
// 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
}
Beispiel #4
0
// 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)
		}
	}()
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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
}
Beispiel #7
0
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
}